知识图谱项目前端可视化图论库——Cytoscape.js简介
前言
知识图谱项目是一个强视觉交互性的关系图可视化分析系统,很多模块都会涉及到对节点和关系的增删改查操作,常规的列表展示类数据通过表格展示,表单新增或编辑,而图谱类项目通常需要关系图(力导向图:又叫力学图、力导向布局图,是绘图的一种算法,关系图一般采用这种布局方式)去展示,节点和关系的新增编辑也需要前端去做一些复杂的交互设计。除此之外还有节点和关系的各种布局算法,大量数据展示的性能优化,节点动态展开时的局部布局渲染,画布的可扩展性,样式的自定义等等诸多技术难点。目前国内使用最多的两个已开源的前端可视化框架:阿里的AntV、百度的Echarts对于关系图的支持都比较弱,不能完全满足项目中的需求。
在之前的两个图谱demo项目中我一直是使用的D3.js这个前端最流行的可视化图库。D3.js也是比较强大的图库,但是它提供的API都是偏底层的,文档也不友好,比较难上手,实现一个简单的功能也需要大量的代码,编码效率并不是很高,各个版本之间兼容性也很差,并且使用SVG渲染画布在大量节点显示的时候有性能瓶颈。
直到我遇见了Cytoscape.js——一个非常适合做知识图谱的前端可视化图库。
先看看cytoscape.js是什么
cytoscape是一个网络图的可视化工具,大量的生物分子/基因领域的公司用它来做可视化分析。由于它的通用性,慢慢的也被其他领域的人用来做网络的可视化和分析。cytoscape分为两种,一种叫做cytoscape desktop,是一个桌面软件,可以把数据导入然后生成可视化的网络图进行分析;另一种叫做cytoscape.js,是一个javascript库,主要给开发人员使用,来在网页上生成可视化的网络图。我们要用的是后者。
官方介绍
Cytoscape.js是一个用原生JS编写的开源图论(又名网络)库。你可以使用Cytoscape.js进行图形分析和可视化。
Cytoscape.js允许你轻松显示和操作丰富的交互式图形。由于Cytoscape.js允许用户与图形进行交互,并且库允许客户端挂接到用户事件,因此Cytoscape.js可以轻松集成到你的应用程序中,尤其是因为Cytoscape.js支持桌面浏览器(例如Chrome)和移动浏览器,就像在iPad上一样。Cytoscape.js包含了开箱即用的所有手势,包括捏缩放,框选择,平移等。
Cytoscape.js还考虑了图分析:该库包含图论中的许多有用功能。你可以在Node.js上无头使用Cytoscape.js在终端或Web服务器上进行图形分析。
Cytoscape.js支持许多不同的图论用例。它支持有向图,无向图,混合图,循环,多图,复合图(一种超图),等等。
兼容所有现代浏览器、具有ES5和canvas支持的旧版浏览器。
安装
CND引入
如果要从CDN使用Cytoscape.js,请使用以下CDN之一:
NPM安装
npm install cytoscape |
Bower安装
bower install cytoscape |
ESM环境中使用
import cytoscape from 'cytoscape'; |
CommonJS环境中使用
var cytoscape = require('cytoscape'); |
AMD / Require.js一起使用
require(['cytoscape'], function(cytoscape){ // ... }); |
入门和基本用法
<!DOCTYPE> <html> <head> <title>cytoscape demo</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script> <style> body { font-family: helvetica neue, helvetica, liberation sans, arial, sans-serif; font-size: 14px } #cy { position: absolute; left: 0; top: 0; bottom: 0; right: 0; z-index: 1; } h1 { opacity: 0.5; font-size: 1em; font-weight: bold; } </style> <script> document.addEventListener('DOMContentLoaded', function () { var cy = window.cy = cytoscape({ container: document.getElementById('cy'), style: [ { selector: 'node', style: { 'content': 'data(id)' } }, { selector: 'edge', style: { 'curve-style': 'bezier', 'target-arrow-shape': 'triangle' } } ], elements: { nodes: [ { data: { id: 'a' } }, { data: { id: 'b' } } ], edges: [ { data: { id: 'ab', source: 'a', target: 'b' } } ] }, layout: { name: 'grid' } }); }); </script> </head> <body> <h1>cytoscape demo</h1> <div id="cy"></div> </body> </html> |
架构和API
使用Cytoscape.js,开发者需要关注体系结构中的两个组件,即核心(即图形实例)和集合。在Cytoscape.js中,核心是开发者进入库的主要入口点。开发者可以从整体上运行布局,更改视口并在整个图形上执行其他操作。
核心提供了几种访问图中元素的函数。这些函数中的每一个都返回一个集合,即图形中的一组元素。集合上有可用的函数,这些函数使开发者可以过滤集合,对集合执行操作,遍历有关集合的图,获取有关集合中元素的数据等等。
有几种类型可以执行不同的功能,在文档中用来表示这些类型的变量名概述如下:
变量名 | 功能描述 |
---|---|
cy |
核心 |
eles |
一个或多个元素(节点和边)的集合 |
ele |
单个元素(节点或边)的集合 |
nodes |
一个或多个节点的集合 |
node |
单节点的集合 |
edges |
一个或多个边的集合 |
edge |
单边的集合 |
layout |
布局 |
ani |
动画 |
默认情况下,函数会将引用返回给调用对象,以允许链接(例如obj.fn1().fn2().fn3()
)。除非另有说明,否则函数可以这种方式链接,除非指定了不同的返回值。这适用于核心和集合。
核心
核心对象是图形的界面。这是进入Cytoscape.js的入口:通过此对象可以访问库的所有功能。
创建核心:
var cy = cytoscape({ /* options */ }); |
你可以初始化内核,而无需任何选项。如果要将Cytoscape用作可视化对象,则需要container
DOM元素,例如:
var cy = cytoscape({ container: document.getElementById('cy') }); |
集合
集合包含一组节点和边。调用函数会将函数应用于集合中的所有元素。从集合中读取值时,例如eles.data()将返回集合中第一个元素的值。例如:
var weight = cy.nodes().data("weight"); console.log( cy.nodes()[0].data("weight") + ' == ' + weight ); // weight is the first ele's weight |
通过使用选择器将集合缩小到一个元素(即eles.size() === 1)或eles.eq()函数,可以确保你正在读取所需的元素。
初始化选项
Cytoscape.js实例具有许多可以在初始化时设置的选项。下面概述了它们的默认值。
请注意,所有内容都是可选的。默认情况下,你将获得带有默认样式表的空图。为了方便起见,浏览器外部的环境(例如Node.js)自动设置为无头。
var cy = cytoscape({ // very commonly used options container: undefined, elements: [ /* ... */ ], style: [ /* ... */ ], layout: { name: 'grid' /* , ... */ }, // initial viewport state: zoom: 1, pan: { x: 0, y: 0 }, // interaction options: minZoom: 1e-50, maxZoom: 1e50, zoomingEnabled: true, userZoomingEnabled: true, panningEnabled: true, userPanningEnabled: true, boxSelectionEnabled: true, selectionType: 'single', touchTapThreshold: 8, desktopTapThreshold: 4, autolock: false, autoungrabify: false, autounselectify: false, // rendering options: headless: false, styleEnabled: true, hideEdgesOnViewport: false, textureOnViewport: false, motionBlur: false, motionBlurOpacity: 0.2, wheelSensitivity: 1, pixelRatio: 'auto' }); |
非常常用的选项:
container
:一个HTML DOM元素,呈现图形的容器。如果Cytoscape.js无头运行,则未指定。该容器应为空div。
elements
:指定为纯对象的元素数组。为了方便起见,也可以将此选项指定为可解析为JSON元素的Promise。
style
:用于设置图形样式的样式表。为了方便起见,也可以将此选项指定为解析为样式表的Promise。
layout
:指定布局选项的普通对象。该name
字段最初指定运行哪个布局。有关布局支持的选项,请参考布局的文档。如果要在元素JSON中自己指定节点位置,则可以使用preset
布局-默认情况下,它不设置任何位置,而将节点保留在当前位置(即options.elements
在初始化时指定)。
初始视口状态:
zoom
:图形的初始缩放级别。确保fit
在布局中禁用视口操纵选项,例如,以便在应用布局时不会覆盖它。你可以设置options.minZoom
和options.maxZoom
设置缩放级别的限制。
pan
:图形的初始平移位置。请确保fit
在布局中禁用视口操纵选项,例如,以便在应用布局时不会覆盖它。
互动选项:
minZoom
:图形缩放级别的最小界限。视口的缩放比例不能小于此缩放级别。
maxZoom
:图形的缩放级别的最大界限。视口的缩放比例不能大于此缩放级别。
zoomingEnabled
:是否通过用户事件和以编程方式启用了缩放图形。
userZoomingEnabled
:是否允许用户事件(例如,鼠标滚轮,捏缩放)缩放图形。缩放的程序更改不受此选项的影响。
panningEnabled
:是否通过用户事件和以编程方式启用了平移图表。
userPanningEnabled
:是否允许用户事件(例如,拖动图形背景)来平移图形。平移的编程更改不受此选项的影响。
boxSelectionEnabled
:是否启用了框选择(即,拖动框叠加并释放它以进行选择)。如果在启用了平移的同时启用了该功能,则用户必须使用修饰键(Shift,Alt,Control或Command)才能使用框选择。
selectionType
:一个字符串,指示用户输入的选择行为。对于'additive'
,用户做出的新选择将添加到当前选择的元素集中。对于'single'
,用户进行的新选择将成为当前所选元素的整个集合(即,未选择先前的元素)。
touchTapThreshold
&desktopTapThreshold
:一个非负整数,指示用户在轻击手势期间分别在触摸设备和台式设备上可以移动的最大允许距离。这使用户更容易点击。这些值具有默认值,因此除非有充分的理由,否则不建议更改这些选项。较大的值几乎肯定会产生不良后果。
autoungrabify
:默认情况下是否应取消节点的节点化(用户不可抓取)(如果true
,则覆盖单个节点状态)。
autolock
:默认情况下是否应锁定节点(完全不可拖动)(如果true
,则覆盖单个节点状态)。
autounselectify
:默认情况下是否应取消选择节点(不可变的选择状态)(如果true
,则覆盖单个元素的状态)。
渲染选项:
headless
:一个方便的选项,用于初始化实例以使其无头运行。你无需在隐式无头的环境(例如Node.js)中进行设置。但是,headless: true
如果要在浏览器中使用无头实例,则设置起来很方便。
styleEnabled
:一个布尔值,指示是否应使用样式。对于无头(即,在浏览器外部)环境,不需要显示,也不需要样式设置,从而加快了代码的速度。如果在特殊情况下需要样式,则可以在无头环境中手动启用样式。请注意,如果计划渲染图形,则禁用样式没有意义。还要注意,cy.destroy()
必须调用来清理启用样式的无头实例。
hideEdgesOnViewport
:渲染提示,当设置为时,true
将使渲染器在操纵视口时不渲染边缘。这使得平移,缩放,拖动等等对于大型图形的响应更加灵敏。由于性能增强,现在该选项几乎没有意义。
textureOnViewport
:一种渲染提示,设置为时,true
使渲染器在平移和缩放过程中使用纹理而不是绘制元素,从而使大型图形更具响应性。由于性能增强,现在该选项几乎没有意义。
motionBlur
:渲染提示,设置为时,true
使渲染器使用运动模糊效果使帧之间的过渡看起来更平滑。这可以提高大型图的感知性能。由于性能增强,现在该选项几乎没有意义。
motionBlurOpacity
:当时motionBlur: true
,此值控制运动模糊帧的不透明度。较高的值会使运动模糊效果更加明显。由于性能增强,现在该选项几乎没有意义。
wheelSensitivity
:更改变焦时的滚轮灵敏度。这是一个乘法修饰符。因此,介于0和1之间的值会降低灵敏度(缩放较慢),而大于1的值会提高灵敏度(缩放较快)。此选项设置为一个合理的值,该值对于Linux,Mac和Windows上的主流鼠标(Apple,Logitech,Microsoft)非常有效。如果默认值在你的特定系统上看起来太快或太慢,则你的操作系统或专用鼠标可能具有非默认鼠标设置。除非你的应用只能在特定硬件上运行,否则你不应更改此值。否则,冒着使大多数用户缩放得太慢或太快的风险。
pixelRatio
:使用手动设置的值(1.0
建议,如果设置)覆盖屏幕像素比率。通过减少需要渲染的有效区域,可以将其用于提高高密度显示器的性能,尽管在最新的浏览器版本中,此需求要小得多。如果要使用硬件的实际像素比率,则可以设置pixelRatio: 'auto'
(默认)。
下面着重介绍一下cytoscape.js中几个非常重要且功能强大的模块,也是我在知识图谱项目中使用最多的模块。
一、选择器
一些注意事项:选择器的功能类似于DOM元素上的CSS选择器,但Cytoscape.js中的选择器可用于图形元素的集合。注意,如果选择器被指定为函数的参数,那么可以使用els .filter()样式的过滤器函数来代替选择器
cy.$('#j').neighborhood(function( ele ){ return ele.isEdge(); }); |
选择器可以组合在一起,以在Cytoscape.js中进行强大的查询,例如:
// get all nodes with weight more than 50 and height strictly less than 180 cy.elements("node[weight >= 50][height < 180]"); |
选择器可以用逗号连接在一起(有效地创建逻辑或):
// get node j and the edges coming out from it cy.elements('node#j, edge[source = "j"]'); |
重要的是要注意,字符串需要用引号引起来:
//cy.filter('node[name = Jerry]'); // this doesn't work cy.filter('node[name = "Jerry"]'); // but this does |
请注意,对于ID,字段名称等,需要转义一些字符:
cy.filter('#some\\$funky\\@id'); |
这些字符的一些示例包括( ^ $ \ / ( ) | ? + * [ ] { } , . )
。尽量避免使用非字母数字字符作为字段名称和ID,以使事情变得简单。如果必须对ID使用特殊字符,请使用数据选择器而不是ID选择器:
cy.filter('[id = "some$funky@id"]'); |
组、类、ID选择器
node
, edge
或*
(组选择器) 基于组匹配元素(node对应
节点,edge
对应边缘,*
对应所有)。
.className
匹配具有指定类的元素(例如,.foo
用于名为“ foo”的类的元素)。
#id
匹配具有匹配ID的元素(例如#foo等效于
[id = 'foo']
)
数据选择器
[name]
如果元素具有定义的指定数据属性(即未定义)undefined
(例如,[foo]
对于名为“ foo”的属性),则匹配元素。在此,null
被认为是定义值。
[^name]
如果未定义指定的数据属性undefined
(例如[^foo]
),则匹配元素。在此,null
被认为是定义值。
[?name]
如果指定的data属性为真值(例如[?foo]
),则匹配元素。
[!name]
如果指定的data属性为falsey值,则匹配元素(例如[!foo]
)。
[name = value]
如果元素的数据属性与指定值匹配(例如[foo = 'bar']
或[num = 2]
),则匹配元素。
[name != value]
如果元素的数据属性与指定值不匹配(例如[foo != 'bar']
或[num != 2]
),则匹配元素。
[name > value]
如果元素的数据属性大于指定值(例如[foo > 'bar']
或[num > 2]
),则与之匹配。
[name >= value]
如果元素的数据属性大于或等于指定值(例如[foo >= 'bar']
或[num >= 2]
),则匹配它们。
[name < value]
如果元素的数据属性小于指定值(例如[foo < 'bar']
或[num < 2]
),则匹配它们。
[name <= value]
如果元素的数据属性小于或等于指定值(例如[foo <= 'bar']
或[num <= 2]
),则匹配它们。
[name *= value]
如果元素的数据属性包含指定的值作为子字符串(例如[foo *= 'bar']
),则与之匹配。
[name ^= value]
如果元素的数据属性以指定值(例如[foo ^= 'bar']
)开头,则与之匹配。
[name $= value]
如果元素的数据属性以指定值(例如[foo $= 'bar']
)结尾,则与之匹配。
@
(数据属性操作者调节剂) 预先考虑的操作,使得不区分大小写(例如[foo @$= 'ar']
,[foo @>= 'a']
,[foo @= 'bar']
)
!
(数据属性运算符修饰符) 加在运算符之前,以便取反(例如[foo !$= 'ar']
,[foo !>= 'a']
)
[[]]
(元数据括号) 使用双方括号代替方括号,以匹配元数据而不是数据(例如,[[degree > 2]]
匹配度数大于2的元素)。所支持的特性包括degree
,indegree
,和outdegree
。
复合选择器
>
(子选择器) 匹配父节点的直接子代(例如node > node
)。
空格(后代选择器) 匹配父节点的后代(例如node node
)。
$
(主题选择器) 设置选择器的主题(例如$node > node
,选择父节点而不是子节点)。
状态选择器
动画
:animated
:匹配当前正在设置动画的元素。:unanimated
:匹配当前未设置动画的元素。
选择
:selected
:匹配选定的元素。:unselected
:匹配未选中的元素。:selectable
:匹配可选元素。:unselectable
:匹配无法选择的元素。
锁定
:locked
:匹配锁定的元素。:unlocked
:匹配未锁定的元素。
样式
:visible
:匹配可见的元素(例如display: element
和visibility: visible
)。:hidden
:匹配隐藏的元素(即display: none
或visibility: hidden
)。:transparent
:匹配透明的元素(例如,opacity: 0
针对自己或父母)。:backgrounding
:如果当前正在加载其背景图像,则匹配该元素。:nonbackgrounding
:如果当前未加载背景图片,则匹配该元素;即没有图像或图像已经加载)。
用户互动:
:grabbed
:匹配用户抓取的元素。:free
:匹配用户当前未捕获的元素。:grabbable
:匹配用户可抓取的元素。:ungrabbable
:匹配用户不可抓取的元素。:active
:匹配活动的元素(即用户交互,类似于:active
CSS)。:inactive
:匹配无效的元素(即无用户交互)。:touch
:在基于触摸的环境中(例如在平板电脑上)显示时,匹配元素。
图表内或图表外
:removed
:匹配从图中删除的元素。:inside
:匹配图中的元素(不会删除它们)。
复合节点
:parent
:匹配父节点(它们具有一个或多个子节点)。:childless
:匹配无子节点(它们有零个子节点)。:child
或:nonorphan
:匹配子节点(它们每个都有一个父节点)。:orphan
:匹配孤立节点(每个节点都没有父节点)。:compound
:匹配父节点。还匹配连接到父节点的边(每个边在源节点和目标节点中至少有一个父节点)。
边缘
:loop
:匹配循环边(与目标源相同)。:simple
:匹配简单边缘(即,就像在简单图形中一样,将不同的源作为目标)。
二、样式
Cytoscape.js中的样式尽可能遵循CSS约定。在大多数情况下,属性与其对应的CSS同名具有相同的名称和行为。但是,CSS中的属性不足以指定图形某些部分的样式。在这种情况下,将引入Cytoscape.js特有的其他属性。
为了简化和易于使用,在样式表中完全忽略了特异性规则。对于给定元素的给定样式属性,最后一个匹配的选择器获胜。
示例
字符串格式: cytoscape({ container: document.getElementById('cy'), // ... style: 'node { background-color: green; }' // probably previously loaded via ajax rather than hardcoded // , ... }); JSON格式: cytoscape({ container: document.getElementById('cy'), // ... style: [ { selector: 'node', style: { 'background-color': 'red' } } // , ... ] // , ... }); 函数格式: cytoscape({ container: document.getElementById('cy'), // ... style: cytoscape.stylesheet() .selector('node') .style({ 'background-color': 'blue' }) // ... // , ... }); |
还可以选择使用css
代替style
,例如.selector( ... ).css( ... )
或{ selector: ..., css: ... }。
三、事件
事件冒泡
所有发生在元素上的事件都会冒泡到复合父元素,然后到达核心。当你在监听核心的时候,你必须考虑到这一点,这样你才能区分发生在背景上的事件和发生在元素上的事件。使用eventObj.target表示事件的发起者(即eventObj.target=== cy || eventObj.target === someEle)。
用户输入设备事件
这些是正常的浏览器事件,你可以通过Cytoscape.js进行监听。你可以在核心和集合上监听这些事件。
mousedown
:按下鼠标按钮时mouseup
:释放鼠标按钮时click
:单击鼠标按钮时mouseover
:将光标放在目标上方时mouseout
:当光标从目标移出时mousemove
:当光标移动到目标上方的某个位置时touchstart
:当一根或多根手指开始触摸屏幕时touchmove
:当一个或多个手指在屏幕上移动时touchend
:从屏幕上移开一根或多根手指时
你还可以使用一些更高级别的事件,因此你不必为鼠标输入设备和触摸设备监听其他事件。
tapstart
或vmousedown
:标准化的点击启动事件tapdrag
或vmousemove
:标准化的使用鼠标左键拖拽移动事件tapdragover
:拖拽到元素之上tapdragout
:拖拽到元素之外tapend
或vmouseup
:标准化的点击结束事件tap
或vclick
:标准化的点击事件taphold
:标准化的点击保持事件cxttapstart
:标准化的右键单击或两指轻敲开始cxttapend
:标准化的右键单击或两指轻敲结束cxttap
:正常右击或两指轻敲cxtdrag
:使用鼠标右键移动或两指拖动cxtdragover
:通过遍历节点时正常右击或两指轻敲cxtdragout
:通过离开节点时正常右击或两指轻敲boxstart
:开始选择框时boxend
:结束框选择时boxselect
:由框选择选择时在元素上触发box
:在框内打开时在元素上触发boxend
集合事件
这些事件是Cytoscape.js自定义的。你可以在集合上监听这些事件。
- tapstart或vmousedown:标准化的轻按开始事件(mousedown或touchstart)
- tapdrag或vmousemove:规范化的移动事件(touchmove或mousemove)
- tapdragover:在元素事件之上的标准化事件(touchmove或mousemove / mouseover)
- tapdragout:在元素事件之外的标准化事件(touchmove或mousemove / mouseout)
- tapend或vmouseup:标准化的点击结束事件(mouseup或touchend)
- tap或vclick:标准化的点击事件(单击或touchstart,然后是touchend,而没有touchmove)
- taphold:标准化的鼠标保持事件
- cxttapstart:标准化的右键单击按下或两指点击
- cxttapend:标准化的右键单击抬起或两指点击
- cxttap:标准化的右键单击或两指点击
- cxtdrag:在cxttapstart之后但在cxttapend之前进行标准化的鼠标移动或两指拖动
- cxtdragover:鼠标右键拖拽经过节点时
- cxtdragout:鼠标右键拖拽离开节点时
- boxstart:开始选择框时
- boxend:结束框选择时
- boxselect:通过框选选择时在元素上触发
- box:在boxend的框内时在元素上触发
图事件
这些事件是Cytoscape.js的自定义事件,它们发生在核心上。
layoutstart
:布局开始运行时layoutready
:当布局已为所有节点设置初始位置(但可能未设置最终位置)时layoutstop
:版式完全完成运行或停止运行时ready
:当准备与Cytoscape.js的新实例进行交互时destroy
:当调用显式销毁Cytoscape.js实例时.destroy()
。render
:(重新)渲染视口时pan
:平移视口时zoom
:缩放视口时viewport
:更改视口时(例如pan
,zoom
在缩放某个点时从,或从两者同时缩放-例如,捏到缩放)resize
:调整视口大小时(通常通过调用cy.resize()
,window
调整大小或在Cytoscape.js div上切换类)
四、布局
布局的功能是设置图中节点上的位置。布局是Cytoscape.js的扩展,因此任何人都可以编写布局而无需修改库本身。
默认情况下,Cytoscape.js包含几种布局,它们的选项都指定了默认值。请注意,必须设置options.name
布局的名称以指定要运行的布局。
每个布局都有其自己的算法,用于设置每个节点的位置。此算法影响图形的整体形状和边的长度。可以通过设置布局的选项来自定义布局的算法。因此,可以通过适当设置布局选项来控制边缘长度。
对于力导向(物理)布局,通常可以选择为每个边缘设置权重以影响相对边缘长度。边缘长度也可能受诸如间距系数,角度和避免重叠等选项的影响。设置边缘长度取决于特定的布局,某些布局将允许比其他布局更精确的边缘长度。
Cytoscape.js自带了一下几种布局:
null :空布局将所有节点放在(0,0)处,这对于调试非常有用。
let options = { name: 'null', ready: function(){}, // on layoutready stop: function(){} // on layoutstop }; cy.layout( options ); |
random :随机布局将节点放置在视口内的随机位置。
let options = { name: 'random', fit: true, // whether to fit to viewport padding: 30, // fit padding boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function ( node, i ){ return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function (node, position ){ return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; cy.layout( options ); |
preset :预设布局将节点放置在手动指定的位置。
let options = { name: 'preset', positions: undefined, // map of (node id) => (position obj); or function(node){ return somPos; } zoom: undefined, // the zoom level to set (prob want fit = false if set) pan: undefined, // the pan level to set (prob want fit = false if set) fit: true, // whether to fit to viewport padding: 30, // padding on fit animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function ( node, i ){ return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function (node, position ){ return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; cy.layout( options ); |
该布局有一个非常实用的地方是,当你保存画布并保存了节点元素的位置后,再加载已保存的画布的时候,可以采用此布局方式。
grid :网格布局将节点放置在一个间隔均匀的网格中。
let options = { name: 'grid', fit: true, // whether to fit the viewport to the graph padding: 30, // padding used on fit boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space avoidOverlapPadding: 10, // extra spacing around nodes when avoidOverlap: true nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm spacingFactor: undefined, // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up condense: false, // uses all available space on false, uses minimal space on true rows: undefined, // force num of rows in the grid cols: undefined, // force num of columns in the grid position: function( node ){}, // returns { row, col } for element sort: undefined, // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') } animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function ( node, i ){ return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function (node, position ){ return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; cy.layout( options ); |
circle :圆圈布局将节点放在圆圈中。
let options = { name: 'circle', fit: true, // whether to fit the viewport to the graph padding: 30, // the padding on fit boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } avoidOverlap: true, // prevents node overlap, may overflow boundingBox and radius if not enough space nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm spacingFactor: undefined, // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up radius: undefined, // the radius of the circle startAngle: 3 / 2 * Math.PI, // where nodes start in radians sweep: undefined, // how many radians should be between the first and last node (defaults to full circle) clockwise: true, // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false) sort: undefined, // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') } animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function ( node, i ){ return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function (node, position ){ return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; cy.layout( options ); |
concentric :同心圆布局将节点放置在同心圆中,基于你指定的将节点隔离到各个级别的度量。此布局在ele.scratch()中设置同心值。
let options = { name: 'concentric', fit: true, // whether to fit the viewport to the graph padding: 30, // the padding on fit startAngle: 3 / 2 * Math.PI, // where nodes start in radians sweep: undefined, // how many radians should be between the first and last node (defaults to full circle) clockwise: true, // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false) equidistant: false, // whether levels have an equal radial distance betwen them, may cause bounding box overflow minNodeSpacing: 10, // min spacing between outside of nodes (used for radius adjustment) boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm height: undefined, // height of layout area (overrides container height) width: undefined, // width of layout area (overrides container width) spacingFactor: undefined, // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up concentric: function( node ){ // returns numeric value for each node, placing higher nodes in levels towards the centre return node.degree(); }, levelWidth: function( nodes ){ // the letiation of concentric values in each level return nodes.maxDegree() / 4; }, animate: false, // whether to transition the node positions animationDuration: 500, // duration of animation in ms if enabled animationEasing: undefined, // easing of animation if enabled animateFilter: function ( node, i ){ return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts ready: undefined, // callback on layoutready stop: undefined, // callback on layoutstop transform: function (node, position ){ return position; } // transform a given node position. Useful for changing flow direction in discrete layouts }; cy.layout( options ); |
breadthfirst :广度优先布局基于图的广度优先遍历将节点置于层次结构中。
cose :cose(复合弹簧嵌入器)布局使用物理模拟对图形进行布局。 它适用于非复合图,并且具有附加逻辑以很好地支持复合图。
五、第三方扩展
UI扩展
-
anywhere-panning
:在节点或边缘上拖动时允许平移。 -
automove
:根据指定的规则(例如,同步节点移动,约束移动等)自动更新节点位置 -
autopan-on-drag
:将节点拖动到视口边界之外时,将自动平移视口。 -
canvas
:在Cytoscape图形上方或下方创建画布的扩展。用于自定义节点/边线,工程图背景等。 -
cerebralweb
:可以对基于亚细胞定位或其他自定义注释进行分层的分子相互作用网络进行快速且交互式的可视化。 -
compound-drag-and-drop
:用于添加和删除子项的复合节点拖放UI -
context-menus
:传统的右键菜单 -
cxtmenu
:圆形上下文菜单,允许在图形上进行一次轻扫命令。 -
edge-bend-editing
:用于编辑边缘折弯(段边缘和贝塞尔曲线边缘)的UI -
edge-editation
:向节点添加句柄,并允许创建不同类型的边缘 -
edge-connections
:根据数据的关联模型,允许边缘在视觉上连接其他边缘。 -
edgehandles
:用于连接具有边缘的节点的UI。 -
even-parent
:无论有多少子元素,都可以调整子元素的尺寸以适合父元素的布局。 -
expand-collapse
:提供用于扩展和折叠复合父节点的API -
grid-guide
:向Cytoscape图形添加网格和捕捉功能 -
navigator
:图形的鸟瞰小部件。 -
no-overlap
:防止节点在拖动时重叠。 -
node-html-label
:允许将HTML指定为节点的标签。 -
node-resize
:具有传统UI的高度可定制的节点大小调整扩展。 -
noderesize
:简约的节点调整大小控件。 -
panzoom
:一个panzoom UI小部件。 -
popper
:Popper.js的包装器,使你可以相对于Cytoscape元素定位div(可与Tippy.js一起使用以创建工具提示)。 -
qtip
:一个包装器,可让你在图形元素或图形背景上使用qTips。 -
snap-to-grid
:向Cytoscape.js图添加网格捕捉和网格线。 -
supportimages
:在Cytoscape.js上支持图像。 -
toolbar
:允许用户创建自定义工具栏,以添加到Cytoscape核心实例的旁边。
布局扩展
-
cola
:Cola.js物理模拟布局。cola可以产生漂亮的布局效果,动画效果非常流畅,并且具有控制布局的绝佳选择。 -
avsdf
:AVSDF布局。它将节点组织成一个圆形,并尝试尽可能减少边缘交叉。 -
cise
:CiSE布局创建圆形簇,并使用物理模拟创建簇之间的距离。 -
cose-bilkent
:Bilkent的CoSE布局,具有增强的复合节点布局。CoSE Bilkent可以提供近乎完美的最终结果。 -
dagre
:用于DAG和树的Dagre布局。 -
elk
:用于Cytoscape.js的ELK布局算法适配器。 -
euler
:Euler是一种快速,小文件大小,高质量的力导向(物理模拟)布局。它对于非复合图非常有用,并且对复合图具有基本支持。 -
fcose
:fCoSE布局是CoSE-Bilkent布局的更快版本。它支持复合图和非复合图,为力导向布局提供顶级的最终结果和高性能。 -
klay
:Klay是适用于大多数图形类型的布局。它为普通图提供了良好的结果,并且可以很好地处理DAG和复合图。 -
ngraph.forcelayout
:一种物理模拟布局,在平面图上特别有效。它相对较快。 -
polywas
:GWAS(全基因组关联研究)数据的布局,说明了基因座之间的关系。 -
spread
:快速的扩展物理模拟布局。它尝试使用所有视口空间,但可以对其进行配置以产生更紧密的结果。最初使用Fruchterman-Reingold,在传播阶段使用Gansner和North。 -
springy
:Springy物理模拟布局。这是基本的物理布局。
API扩展
-
all-paths
:获取所有最长的定向路径。 -
clipboard
:将复制粘贴实用程序添加到Cytoscape.js。 -
dblclick
:向Cytoscape.js 添加双击事件。 -
graphml
:将GraphML导入和导出功能添加到Cytoscape.js。 -
undo-redo
:将撤销重做API添加到Cytoscape.js。 -
view-utilities
:向Cytoscape.js添加搜索和突出显示API。
工具包
-
cytosnap
:一个Node.js程序包,该程序包使用Puppeteer在服务器上呈现Cytoscape.js图的图像。 -
ngx-cytoscape
:Cytoscape.js的Angular 5+组件。 -
react-cytoscapejs
:用于Cytoscape.js网络可视化的React组件。 -
sif.js
:一个用于解析简单交互文件(SIF)文件的JavaScript库。 -
sbgn-stylesheet
:为SBGN预设的样式表。 -
sbgnml-to-cytoscape
:将基于XML的SBGN文件转换为Cytoscape.js JSON。 -
vue-cytoscape
:Cytoscape.js 的Vue组件。
总结:
cytoscape.js本身是一个开源的用来做图形分析和可视化的JS图论(又名网络)库(graph theory (a.k.a. network)),大量的生物分子和医疗领域的公司或者科研机构在使用。
因为它主要是做网络图或者叫关系图分析,所以非常适合做知识图谱项目,它功能齐全,且使用简单,内置了很多常用的布局算法,路径算法,复合图形,还有丰富的第三方插件,基本上能满足你在项目中的各种需求。
需要关注两个最主要的功能组件----核心(图形实例)和集合,提供了大量的方法供开发者调用去实现你想实现的功能,并且继承了JQuery的很多功能比如选择器、链式调用、甚至连设置css样式都和JQuery如出一辙。所以上手它并熟练使用它不是一件特别难的事。
我现在也只是使用了它很少一部分的功能,大量的高级用法还需要继续深入研究。
本文大量内容都是节选自官方文档翻译过来的,不免会有不太严谨的地方欢迎指出,如果你也对它感兴趣可以访问它的官方文档和github主页:
官方文档:https://js.cytoscape.org/
github主页:https://github.com/cytoscape/cytoscape.js