先上预览地址:http://oxoyo.co/X-Flowchart-Vue/
再上仓库地址:https://github.com/OXOYO/X-Flowchart-Vuejavascript
初衷很简单,开发一个基于Vue的流程编辑器。项目初期研究过jsplumb,不是很理想,后来就着手拿SVG直接堆一个出来,第一版开发完基本知足需求。
在通过了3个版本的迭代后,算是有一个比较成型的编辑器了,下面简单介绍一下。html
该版本使用原生SVG开发,实现了基础的节点拖拽、连线、属性配置、右键菜单、导出数据功能,基本知足项目需求。vue
该版本原计划是在V1.0基础上作功能优化、功能扩展的,但开发了一段时间后以为总体设计不够理想就搁置了。java
该版本是基于 antvis/G6 实现,属于对前两版本的重构。node
目前已实现的功能以下表所示:git
功能 | 状态 | 快捷键 | 工具栏 | 右键菜单 | 备注 |
---|---|---|---|---|---|
logo | ✔ | ✔ | ✖ | Logo | |
undo | ✔ | ctrl + z | ✔ | ✔ | 撤销 |
clearLog | ✔ | ctrl + shift + l | ✔ | ✔ | 清空操做日志 |
redo | ✔ | ctrl + shift + z | ✔ | ✔ | 重作 |
copy | ✔ | ctrl + c | ✔ | ✔ | 复制 |
paste | ✔ | ctrl + v | ✔ | ✔ | 粘贴 |
delete | ✔ | Delete | ✖ | ✔ | 删除 |
clear | ✔ | ctrl + shift + e | ✔ | ✔ | 清空画布 |
zoom | ✔ | ✔ | ✔ | 缩放 | |
zoomIn | ✔ | ctrl + + | ✔ | ✔ | 放大 |
zoomOut | ✔ | ctrl + - | ✔ | ✔ | 缩小 |
fit | ✔ | ctrl + 0 | ✔ | ✔ | 适应屏幕 |
actualSize | ✔ | ctrl + 1 | ✔ | ✔ | 实际大小 |
fill | ✔ | ✔ | ✔ | 填充颜色 | |
lineColor | ✔ | ✔ | ✔ | 线条颜色 | |
lineWidth | ✔ | ✔ | ✔ | 线条宽度 | |
lineStyle | ✔ | ✔ | ✔ | 线条样式 | |
lineType | ✔ | ✔ | ✔ | 线条类型 | |
startArrow | ✔ | ✔ | ✔ | 起点 | |
endArrow | ✔ | ✔ | ✔ | 终点 | |
toFront | ✔ | ✔ | ✔ | 置于顶层 | |
toBack | ✔ | ✔ | ✔ | 置于底层 | |
selectAll | ✔ | ctrl + a | ✔ | ✔ | 全选 |
marquee | ✔ | ✖ | ✖ | 框选 | |
edit | ✔ | ✔ | ✔ | 编辑 | |
preview | ✔ | ✔ | ✔ | 预览 | |
upload | ✔ | ✔ | ✔ | 上传 | |
download | ✔ | ✔ | ✔ | 下载 | |
language | ✔ | ✔ | ✔ | 语言 | |
github | ✔ | ✔ | ✔ | Github | |
feedback | ✔ | ✔ | ✔ | 反馈 |
撤销、清空日志、重作,在 state
中存储 log
数据,经过 mutation
来更新 log
数据。github
statecurrent
就是当前画布上的数据。list
就是操做日志列表。json
// /src/store.js export default new Vuex.Store({ state: { editor: { ... // 操做日志 log: { current: null, list: [] } ... } }, ... mutations: { ... 'editor/log/update': (state, data) => { ... } } })
更新
在须要记录操做的地方经过 commit
editor/currentItem/update
来更新 log
数据canvas
// 更新操做日志 _t.$store.commit('editor/log/update', { // 操做类型:undo、clearLog、redo action: '' })
复制、粘贴,经过 clipboard
存储复制的节点数据,经过 addItem
方法将节点粘贴到画布上。jsp
// /src/components/Editor/Index.vue ... // 数据定义 data () { return { ... clipboard: { data: null, // 粘贴计数器 count: 0 } ... } } ... handleToolTrigger (info) { ... switch (info.name) { ... case 'copy': (() => { // FIXME 目前只支持节点的复制,不支持边的复制,边只能经过拖拽生成 let data = _t.currentItem ? _t.currentItem.filter(item => item.type === 'node') : [] _t.clipboard = { data, count: 0 } })() break case 'paste': (() => { let data = _t.clipboard.data _t.clipboard.count++ if (data.length) { data.forEach((item, index) => { let model = item.model // 计算坐标,添加必定偏移量,防止重叠 let x = model.x + 10 * _t.clipboard.count let y = model.y + 10 * _t.clipboard.count // 若是经过右键菜单触发的,则获取触发菜单时的canvas坐标 if (info && info.context === 'ContextMenu' && info.data) { if (info.data.hasOwnProperty('canvasX')) { x = model.x + info.data.canvasX - data[0].model.x } if (info.data.hasOwnProperty('canvasY')) { y = model.y + info.data.canvasY - data[0].model.y } } let node = { ...model, id: G6.Util.uniqueId(), groupId: '', x, y } // 添加节点到画布上 _t.editor.addItem('node', node) }) } })() break ... } ... }
删除元素,经过 removeItem
方法删除 node
、edge
。
清空画布,经过 clear
方法清空画布。
缩放、放大、缩小,经过 zoomTo
方法将画布缩放到某个比例
适应屏幕,经过 fitView
方法将画布缩放到适应屏幕;经过。
实际大小,经过 zoomTo
方法将画布缩放到 1
比例。
填充颜色、线条颜色、线条宽度、线条样式、线条类型、起点、终点,经过 updateItem
方法更新节点、边的属性。
置顶,经过 toFront
方法将节点、边置顶。
置底,经过 toBack
方法将节点、边置底。
全选,经过 updateItem
方法设置全部节点为同一个 groupId
,经过 setItemState
方法设置全部节点 active
状态。
编辑、预览,经过 setMode
方法设置画布不一样的模式,不一样模式下会执行不一样的 behavior
。
// /src/components/Editor/index.vue // 生成编辑器实例 _t.editor = new G6.Graph({ ... // 模式 modes: { // 编辑模式 edit: [ { // 自定义节点控制交互 type: 'node-control', config: {...} } ], // 预览模式 preview: [ 'zoom-canvas', 'drag-canvas', 'preview-canvas' ] ... })
上传,经过 input
文本选择窗口上传 json
数据文件,经过 FileReader
解析数据,经过 data
设置画布数据,经过 render
渲染画布。
下载,经过 downloadImage
下载为图片,经过 save
下载为 json
数据。
国际化,经过 i18n
处理多语言。
使用 mousetrap 处理快捷键绑定。
在 /src/global/g6/node/
目录下是自定义节点的实现,经过 G6.registerNode
方法注册自定义节点。
在 /src/global/g6/edge/
目录下是自定义边的实现,经过 G6.registerEdge
方法注册自定义边。
在 /src/global/g6/behavior/
目录下是自定义交互的实现,经过 G6.registerBehavior
方法注册自定义交互。
在 /src/global/g6/plugins/
目录下是自定义插件的实现,经过继承扩展插件,在建立实例 new G6.Graph
时使用插件。
产品在开发过程当中参考了如下项目部分实现:
@alibaba/GGEditor
@guozhaolong/wfd
grapheditor
最后欢迎各位大佬 star、pr。