ELK's layout algorithms for JavaScript
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 5 个月前 | ||
| 5 个月前 | ||
| 3 年前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 年前 | ||
| 8 年前 | ||
| 6 年前 | ||
| 1 个月前 | ||
| 5 个月前 | ||
| 11 个月前 | ||
| 7 年前 | ||
| 3 年前 | ||
| 3 年前 | ||
| 1 个月前 | ||
| 1 个月前 |
Eclipse Layout Kernel (ELK) 实现了一种基础设施,用于将图表编辑器或查看器连接到自动布局算法。本库提取了 ELK 中与布局相关的部分,并将其应用于 JavaScript 环境。ELK 的核心是一种基于层的布局算法,特别适用于具有内在方向和端口(节点边界上的显式连接点)的节点链接图。它基于 Sugiyama 等人最初提出的思想。下方截图展示了一个示例。
请注意,elkjs 本身并非绘图框架,它仅计算图表元素的位置。
elkjs 是 klayjs 的继任者。
演示
您可以通过 TypeFox 的 sprotty 绘图框架查看 elkjs 的 在线演示。如果 elklive 暂时无法访问,您可以使用已发布的 docker 容器 自行运行和托管。
常见问题与常见问题
以下列表包含一些可能已在 issue 中解决的常见主题:
-
#100、elk#355、elk#627 - 如何考虑先前的布局结果,包括
- 动态布局,以及
- 向现有布局中增量添加节点和边。
-
elk#315:独立边路由。
-
#85 elkjs 本身仅是一个图形布局引擎。换句话说,它不提供渲染、样式等功能。
-
#127、#141、#142 - 由于 GWT 进行的底层代码转译和/或过时的 js 模块使用导致的问题:
g is not defined,Can't resolve web-worker,以及- 在 react、webpack 等环境中的常规使用问题。
- #6 模块化程度不足
- 欢迎对此处提供贡献!
安装
最新发布版本:
npm install elkjs
基于 ELK master 分支的开发版本。
npm install elkjs@next
发布与版本控制
版本发布在一定程度上与 ELK 的版本保持同步:次要版本号始终一致,但修订号可能会有所不同。例如,elkjs 0.3.0 的功能与 ELK 0.3.0 相当,但 elkjs 0.3.2 可能与 ELK 0.3.2 不同。这是必要的,因为可能存在仅与 elkjs 相关的修复,需要独立于 ELK 进行发布。
文件
该库包含两个主要文件:
elk-api.js:提供 API,并且仅提供 API。elk-worker.js:提供实际执行图布局的代码。此文件是使用 GWT 从 ELK 的 Java 代码库生成的。
另外还提供了两个文件:
elk.bundled.js:上述两个文件的捆绑版本,可直接放入浏览器的<script>标签中使用。该文件经过 browserify 处理,并且在浏览器环境中会将ELK暴露为全局变量。main.js:node.js 模块的主文件。允许通过require('elkjs')方便地引入,而无需手动组合上述文件。
示例
一个使用 node.js 的简单示例, 更多使用场景请参见下一节。
const ELK = require('elkjs')
const elk = new ELK()
const graph = {
id: "root",
layoutOptions: { 'elk.algorithm': 'layered' },
children: [
{ id: "n1", width: 30, height: 30 },
{ id: "n2", width: 30, height: 30 },
{ id: "n3", width: 30, height: 30 }
],
edges: [
{ id: "e1", sources: [ "n1" ], targets: [ "n2" ] },
{ id: "e2", sources: [ "n1" ], targets: [ "n3" ] }
]
}
elk.layout(graph)
.then(console.log)
.catch(console.error)
请注意,如果遇到错误,你可能需要切换到未压缩版本以获取完整的堆栈跟踪。
布局选项
你可以使用_布局选项_来配置布局算法。为此,你需要将一个layoutOptions对象附加到图形元素上,该对象包含表示所需布局选项的键值对。例如,参见上面示例中的root。你可以只使用布局选项的后缀:用algorithm代替org.eclipse.elk.layered。但是,如果后缀不唯一,该布局选项可能会被忽略。为安全起见,布局选项应始终以elk.开头。所有选项的列表及其确切效果的更多详细信息,请参见ELK的文档。
可以将全局布局选项作为layout方法第二个参数的一部分进行传递。这些选项将应用于每个图形元素,除非该元素自身指定了该选项:
elk.layout(graph, {
layoutOptions: { ... }
})
此外,ELK 的构造函数接受一个包含布局选项的对象,该对象会用于所有未指定布局选项的 layout 调用:
const elk = new ELK({
defaultLayoutOptions: { ... }
})
用法
由于绘制图表布局可能是一项耗时的工作(即使对于计算机而言),而且我们不希望冻结您的用户界面,因此 Web Workers 是开箱即支持的。以下示例说明了该库如何在使用和不使用 Web Worker 的情况下进行使用。
node.js
const ELK = require('elkjs')
// without web worker
const elk = new ELK()
elk.layout(graph)
.then(console.log)
const ELK = require('elkjs')
// with web worker
const elk = new ELK({
workerUrl: './node_modules/elkjs/lib/elk-worker.min.js'
})
elk.layout(graph)
.then(console.log)
自 10.x 版本起,node.js 提供了 worker threads 实现,它与浏览器的 Worker 类相似,但并不完全相同。
为了简化我们这边的实现,我们使用了一个名为 web-worker 的库,该库提供了一个围绕 node 的 worker_threads 的包装器,其 API 与浏览器的 Worker 兼容。不过,任何其他提供标准 Web Worker 方法的库也应该适用。
该包不会自动安装,以避免给那些不感兴趣使用 web worker 的用户带来不必要的依赖。
如果有人在未安装该包的情况下请求 web worker,将会发出警告。在这种情况下,elkjs 会回退到非 Web Worker 版本。
浏览器
<html>
<script src="./elk.bundled.js"></script>
<script type="text/javascript">
const elk = new ELK()
elk.layout(graph)
.then(function(g) {
document.body.innerHTML = "<pre>" + JSON.stringify(g, null, " ") + "</pre>"
})
</script>
</html>
<html>
<script src="./elk-api.js"></script> <!-- use elk-api.js here! -->
<script type="text/javascript">
const elk = new ELK({
workerUrl: './elk-worker.js'
})
elk.layout(graph)
.then(function(g) {
document.body.innerHTML = "<pre>" + JSON.stringify(g, null, " ") + "</pre>"
})
</script>
</html>
TypeScript
import ELK from 'elkjs/lib/elk.bundled.js'
const elk = new ELK()
import ELK from 'elkjs/lib/elk-api'
const elk = new ELK({
workerUrl: './elk-worker.min.js'
})
调试
出于调试目的,您可能希望使用同样可用的非压缩版本。 在这种情况下,可以按如下方式配置非压缩的 Web Worker 版本:
const ELK = require('elkjs/lib/elk-api.js')
const elk = new ELK({
workerFactory: function(url) { // the value of 'url' is irrelevant here
const { Worker } = require('elkjs/lib/elk-worker.js') // non-minified
return new Worker(url)
}
})
API
elkjs 库提供了一个对象:ELK。ELK 有一个可用于构造它的构造函数:
new ELK(options)- 可向ELK传入选项,所有选项都是可选的:defaultLayoutOptions- 一个包含默认布局选项的对象,这些选项以键值对形式指定。如果未向layout(graph, options)方法(见下文)传递更多布局选项,则使用这些默认选项。默认值:{}。algorithms- 算法 ID 数组(仅后缀)。默认值:[ 'layered', 'stress', 'mrtree', 'radial', 'force', 'disco' ]。注意,box、fixed和random布局器始终包含在内。workerUrl-elk-worker.js脚本的路径。因此,ELK将使用 Web Worker 来执行布局。默认值:undefined。
除此之外,ELK 还提供以下方法:
layout(graph, options)graph- 要进行布局的图,采用 ELK JSON 格式。必填项!options- 配置对象。可选。layoutOptions:其最重要的用途是传递全局布局选项。即,这些布局选项将应用于每个图元素,除非该元素自身指定了该选项。logging:布尔值(自 0.6.0 版本起)。是否应将日志信息作为已布局图的一部分返回。默认值为false。measureExecutionTime:布尔值(自 0.6.0 版本起)。是否应将执行时间(以秒为单位)信息作为已布局图的一部分返回。默认值为false。
- 返回一个
Promise,成功时传递已布局的图,失败时传递(希望是有帮助的)错误信息。
knownLayoutOptions()- 返回已知布局选项的数组。对于每个选项,会提供额外信息,例如其
id和group。
- 返回已知布局选项的数组。对于每个选项,会提供额外信息,例如其
knownLayoutAlgorithms()- 返回已注册布局算法的数组(见上文)以及每个算法的进一步信息。
knownLayoutCategories()- 返回已注册布局类别的数组。
terminateWorker()- 如果使用了 Web Worker,将调用 worker 的terminate()方法。
以 known 开头的三个方法基本上返回的信息,在 Java 环境中,可以从 LayoutMetaDataService 中获取。
日志和执行时间
(自 0.6.0 版本起)
ELK 提供了一些方法,用于在布局算法执行期间记录调试信息。详细内容可在 ELK 文档的 “算法调试” 部分找到。不过,并非所有功能在 elkjs 中都可用,例如,无法保存已布局图形的中间结果。此外,在 Java 端,内部执行时间以纳秒为单位进行测量,而在 elkjs 中,我们不得不采用毫秒。请注意,返回的执行时间以秒为单位。对于小型图形,报告的执行时间常常可能为 0。
以下是示例调用和示例输出。
elk.layout(simpleGraph, {
layoutOptions: {
'algorithm': 'layered'
},
logging: true,
measureExecutionTime: true
})
{
"id": "root",
"children": [ ... ],
"edges": [ ... ],
"logging": {
"name": "Recursive Graph Layout",
"executionTime": 0.000096,
"children": [ {
"name": "Layered layout",
"logs": [
"ELK Layered uses the following 17 modules:",
" Slot 01: org.eclipse.elk.alg.layered.p1cycles.GreedyCycleBreaker",
[ ... ]
" Slot 16: org.eclipse.elk.alg.layered.intermediate.ReversedEdgeRestorer"
],
"executionTime": 0.000072,
"children": [ { "name": "Greedy cycle removal", "executionTime": 0.000002 },
[ ... ]
{ "name": "Restoring reversed edges", "executionTime": 0 } ]
} ]
}
}
构建
构建时,需要检出 ELK 代码库,且该代码库应与本代码库的检出目录位于同一目录下。具体如下:
some_dir/
├── elkjs
└── elk
npm install
npm run build
对于新版本发布,需要修改以下版本号:
package.json中的version,build.gradle中的melk,以及- 不要忘记检出 ELK 仓库的正确发布标签。
之后,你可以在 lib 文件夹中找到生成的文件。
当前流程
git checkout -b releases/0.x.x
# Check that the version numbers are correct, if necessary update versions and commit the changes
npm install
npm run build
npm run test
# Add ./lib/ directory and commit
git tag 0.x.x
# Push release branch and tags to remote
git push --tags --set-upstream origin releases/0.x.x
# Create a new release on Github for the new tag and afterwards publish to npm
Once the release is published on Github, the release on npm will be automatically triggered
之后,需将以下版本号更改为下一个发布版本号:
package.json中的versionbuild.gradle中的melk
错误的 npm 标签
可使用 npm dist-tag add elkjs@<version> <latest/next> 更新 npm 上标记错误的版本。
链接
以下是一系列其他项目和网站的链接,可能会有所帮助:
- 与 Java ELK 的执行时间对比
- 如何指定节点标签位置
- 如何强制特定的节点定位(拓扑)
elkjs 的示例用户
- 原理图
- netlistsvg - 电子和门级原理图(SVG 格式)
- d3-hwschematic - 交互式数字电路分析和文档,特别适用于基于 FPGA 的设计
- Cytoscape 适配器
- reaflow - 基于 React 和 elkjs 构建的节点编辑器
- reactflow - 用于构建节点编辑器和交互式图表的 React 组件
- 将 elkjs 包装成基于 docker 的微服务
- sprotty - 一个图表框架
- Eclipse 4diac
- capellambse-context-diagrams - 为 Python 中的 Capella 生成系统工程上下文图
- 用于在 Vega Editor 中布局数据流查看器
注:我们很乐意进一步扩展此列表,因此如果您有项目要添加,请联系我们