参考文档:LogicFlow 官方文档
# LogicFlow 是什么
LogicFlow 是一款流程图编辑框架,提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow 支持前端研发自定义开发各种逻辑编排场景,如流程图、ER 图、BPMN 流程等。在工作审批配置、机器人逻辑编排、无代码平台流程配置都有较好的应用。
# 安装 LogicFlow
通过 npm
或 yarn
来安装 LogicFlow
。
# npm | |
$ npm install @logicflow/core --save | |
# yarn | |
$ yarn add @logicflow/core |
安装完成之后,使用 import
或 require
进行引用。
import LogicFlow from '@logicflow/core'; | |
import '@logicflow/core/dist/style/index.css'; |
# 快速上手
# 创建容器
在页面中创建一个用于绘图的容器,可以是一个 div
标签。
<div id="container"></div> |
# 准备数据
通过 JSON
的数据格式,来让 LogicFlow
渲染。该数据中需要有 nodes
(节点) 和 edges
(边) 字段,分别用数组表示:
const data = { | |
// 节点 | |
nodes: [ | |
{ | |
id: 50, | |
type: 'rect', | |
x: 100, | |
y: 150, | |
text: '你好', | |
}, | |
{ | |
id: 21, | |
type: 'circle', | |
x: 300, | |
y: 150, | |
}, | |
], | |
// 边 | |
edges: [ | |
{ | |
type: 'polyline', | |
sourceNodeId: 50, | |
targetNodeId: 21, | |
}, | |
], | |
}; |
# 渲染画布
首先创建一个 LogicFlow
的实例,此时可以传入一些参数来控制画布,比如画布的大小。
const lf = new LogicFlow({ | |
container: document.querySelector('#container'), | |
stopScrollGraph: true, | |
stopZoomGraph: true, | |
width: 500, | |
height: 500, | |
grid: { | |
type: 'dot', | |
size: 20, | |
}, | |
}); |
通过刚才创建的实例,来渲染画布。
lf.render(data); |
到此,我们就创建好了一个最简单的示例。
# 基本使用
LogicFlow 的功能分为核心功能和插件功能。LogicFlow 最初的目标就是支持一个扩展性强的流程绘制工具,用来满足各种业务需求。为了让 LogicFlow 的拓展性足够强,LogicFlow 将所有的非核心功能都使用插件的方式开发,然后将这些插件放到 @logicflow/extension
包中。
核心功能:节点、边、主题、事件、网格、背景、拖拽创建节点、键盘快捷键、对齐线、设置图编辑方式。
插件功能: 菜单、拖拽面板、控制面板、小地图、框选、节点缩放、分组、圆角折线、边上插入节点、数据转换、BPMN 元素、导出、自定义插件。
文档参见:https://site.logic-flow.cn/docs/#/zh/guide/basic/node
# Demo
main.js
import './assets/main.css' | |
import { createApp } from 'vue' | |
import App from './App.vue' | |
createApp(App).mount('#app') |
App.vue
<template> | |
<Lf /> | |
</template> | |
<script> | |
import Lf from "./components/Lf.vue"; | |
export default { | |
name: "App", | |
components: { | |
Lf, | |
}, | |
}; | |
</script> | |
<style> | |
html, | |
body { | |
width: 100%; | |
height: 100%; | |
} | |
#app { | |
font-family: "Avenir", Helvetica, Arial, sans-serif; | |
-webkit-font-smoothing: antialiased; | |
-moz-osx-font-smoothing: grayscale; | |
text-align: center; | |
color: #2c3e50; | |
margin-top: 60px; | |
width: 100%; | |
height: 100%; | |
} | |
</style> |
Lf.vue
<template> | |
<div class="container" ref="container"></div> | |
</template> | |
<script> | |
import LogicFlow from "@logicflow/core"; | |
import { Menu,DndPanel, SelectionSelect} from "@logicflow/extension"; | |
import "@logicflow/core/dist/style/index.css"; | |
import '@logicflow/extension/lib/style/index.css' | |
import UserTask from "../common/UserTask"; | |
export default { | |
mounted() { | |
this.lf = new LogicFlow({ | |
container: this.$refs.container, | |
grid: true, // 是否开启网格背景 | |
keyboard: { | |
enabled: true, //cv 回退 快捷键 | |
}, | |
isSilentMode: false, // 仅浏览不可编辑模式,默认不开启 | |
snapline: false, // 关闭对齐线功能 | |
plugins: [DndPanel, SelectionSelect,Menu], | |
}); | |
this.lf.register(UserTask); | |
this.lf.render({ | |
nodes: [ | |
{ | |
id: "1", | |
type: "rect", | |
x: 150, | |
y: 100, | |
}, | |
{ | |
id: "2", | |
type: "circle", | |
x: 350, | |
y: 200, | |
}, | |
{ | |
id: "3", | |
type: "diamond", | |
x: 500, | |
y: 300 | |
}, | |
], | |
edges: [ | |
{ | |
sourceNodeId: "1", | |
targetNodeId: "2", | |
type: "polyline", | |
}, | |
{ | |
sourceNodeId: "2", | |
targetNodeId: "3", | |
type: "polyline", | |
}, | |
], | |
}); | |
// 拖拽面板 | |
this.lf.extension.dndPanel.setPatternItems([ | |
{ | |
label: '选区', | |
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=', | |
callback: () => { | |
this.lf.extension.selectionSelect.openSelectionSelect(); | |
this.lf.once('selection:selected', () => { | |
this.lf.extension.selectionSelect.closeSelectionSelect(); | |
}); | |
} | |
}, | |
{ | |
type: 'circle', | |
text: '开始', | |
label: '开始节点', | |
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAnBJREFUOBGdVL1rU1EcPfdGBddmaZLiEhdx1MHZQXApraCzQ7GKLgoRBxMfcRELuihWKcXFRcEWF8HBf0DdDCKYRZpnl7p0svLe9Zzbd29eQhTbC8nv+9zf130AT63jvooOGS8Vf9Nt5zxba7sXQwODfkWpkbjTQfCGUd9gIp3uuPP8bZ946g56dYQvnBg+b1HB8VIQmMFrazKcKSvFW2dQTxJnJdQ77urmXWOMBCmXM2Rke4S7UAW+/8ywwFoewmBps2tu7mbTdp8VMOkIRAkKfrVawalJTtIliclFbaOBqa0M2xImHeVIfd/nKAfVq/LGnPss5Kh00VEdSzfwnBXPUpmykNss4lUI9C1ga+8PNrBD5YeqRY2Zz8PhjooIbfJXjowvQJBqkmEkVnktWhwu2SM7SMx7Cj0N9IC0oQXRo8xwAGzQms+xrB/nNSUWVveI48ayrFGyC2+E2C+aWrZHXvOuz+CiV6iycWe1Rd1Q6+QUG07nb5SbPrL4426d+9E1axKjY3AoRrlEeSQo2Eu0T6BWAAr6COhTcWjRaYfKG5csnvytvUr/WY4rrPMB53Uo7jZRjXaG6/CFfNMaXEu75nG47X+oepU7PKJvvzGDY1YLSKHJrK7vFUwXKkaxwhCW3u+sDFMVrIju54RYYbFKpALZAo7sB6wcKyyrd+aBMryMT2gPyD6GsQoRFkGHr14TthZni9ck0z+Pnmee460mHXbRAypKNy3nuMdrWgVKj8YVV8E7PSzp1BZ9SJnJAsXdryw/h5ctboUVi4AFiCd+lQaYMw5z3LGTBKjLQOeUF35k89f58Vv/tGh+l+PE/wG0rgfIUbZK5AAAAABJRU5ErkJggg==', | |
}, | |
{ | |
type: 'UserTask', | |
label: '用户任务', | |
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==', | |
className: 'important-node' | |
}, | |
{ | |
type: 'rect', | |
label: '系统任务', | |
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==', | |
className: 'import_icon' | |
}, | |
{ | |
type: 'diamond', | |
label: '条件判断', | |
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAAHeEJUAAAAABGdBTUEAALGPC/xhBQAAAvVJREFUOBGNVEFrE0EU/mY3bQoiFlOkaUJrQUQoWMGePLX24EH0IIoHKQiCV0G8iE1covgLiqA/QTzVm1JPogc9tIJYFaQtlhQxqYjSpunu+L7JvmUTU3AgmTfvffPNN++9WSA1DO182f6xwILzD5btfAoQmwL5KJEwiQyVbSVZ0IgRyV6PTpIJ81E5ZvqfHQR0HUOBHW4L5Et2kQ6Zf7iAOhTFAA8s0pEP7AXO1uAA52SbqGk6h/6J45LaLhO64ByfcUzM39V7ZiAdS2yCePPEIQYvTUHqM/n7dgQNfBKWPjpF4ISk8q3J4nB11qw6X8l+FsF3EhlkEMfrjIer3wJTLwS2aCNcj4DbGxXTw00JmAuO+Ni6bBxVUCvS5d9aa04+so4pHW5jLTywuXAL7jJ+D06sl82Sgl2JuVBQn498zkc2bGKxULHjCnSMadBKYDYYHAtsby1EQ5lNGrQd4Y3v4Zo0XdGEmDno46yCM9Tk+RiJmUYHS/aXHPNTcjxcbTFna000PFJHIVZ5lFRqRpJWk9/+QtlOUYJj9HG5pVFEU7zqIYDVsw2s+AJaD8wTd2umgSCCyUxgGsS1Y6TBwXQQTFuZaHcd8gAGioE90hlsY+wMcs30RduYtxanjMGal8H5dMW67dmT1JFtYUEe8LiQLRsPZ6IIc7A4J5tqco3T0pnv/4u0kyzrYUq7gASuEyI8VXKvB9Odytv6jS/PNaZBln0nioJG/AVQRZvApOdhjj3Jt8QC8Im09SafwdBdvIpztpxWxpeKCC+EsFdS8DCyuCn2munFpL7ctHKp+Xc5cMybeIyMAN33SPL3ZR9QV1XVwLyzHm6Iv0/yeUuUb7PPlZC4D4HZkeu6dpF4v9j9MreGtMbxMMRLIcjJic9yHi7WQ3yVKzZVWUr5UrViJvn1FfUlwe/KYVfYyWRLSGNu16hR01U9IacajXPei0wx/5BqgInvJN+MMNtNme7ReU9SBbgntovn0kKHpFg7UogZvaZiOue/q1SBo9ktHzQAAAAASUVORK5CYII=', | |
}, | |
{ | |
type: 'circle', | |
text: '结束', | |
label: '结束节点', | |
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAA1BJREFUOBFtVE1IVUEYPXOf+tq40Y3vPcmFIdSjIorWoRG0ERWUgnb5FwVhYQSl72oUoZAboxKNFtWiwKRN0M+jpfSzqJAQclHo001tKkjl3emc8V69igP3znzfnO/M9zcDcKT67azmjYWTwl9Vn7Vumeqzj1DVb6cleQY4oAVnIOPb+mKAGxQmKI5CWNJ2aLPatxWa3aB9K7/fB+/Z0jUF6TmMlFLQqrkECWQzOZxYGjTlOl8eeKaIY5yHnFn486xBustDjWT6dG7pmjHOJd+33t0iitTPkK6tEvjxq4h2MozQ6WFSX/LkDUGfFwfhEZj1Auz/U4pyAi5Sznd7uKzznXeVHlI/Aywmk6j7fsUsEuCGADrWARXXwjxWQsUbIupDHJI7kF5dRktg0eN81IbiZXiTESic50iwS+t1oJgL83jAiBupLDCQqwziaWSoAFSeIR3P5Xv5az00wyIn35QRYTwdSYbz8pH8fxUUAtxnFvYmEmgI0wYXUXcCCSpeEVpXlsRhBnCEATxWylL9+EKCAYhe1NGstUa6356kS9NVvt3DU2fd+Wtbm/+lSbylJqsqkSm9CRhvoJVlvKPvF1RKY/FcPn5j4UfIMLn8D4UYb54BNsilTDXKnF4CfTobA0FpoW/LSp306wkXM+XaOJhZaFkcNM82ASNAWMrhrUbRfmyeI1FvRBTpN06WKxa9BK0o2E4Pd3zfBBEwPsv9sQBnmLVbLEIZ/Xe9LYwJu/Er17W6HYVBc7vmuk0xUQ+pqxdom5Fnp55SiytXLPYoMXNM4u4SNSCFWnrVIzKG3EGyMXo6n/BQOe+bX3FClY4PwydVhthOZ9NnS+ntiLh0fxtlUJHAuGaFoVmttpVMeum0p3WEXbcll94l1wM/gZ0Ccczop77VvN2I7TlsZCsuXf1WHvWEhjO8DPtyOVg2/mvK9QqboEth+7pD6NUQC1HN/TwvydGBARi9MZSzLE4b8Ru3XhX2PBxf8E1er2A6516o0w4sIA+lwURhAON82Kwe2iDAC1Watq4XHaGQ7skLcFOtI5lDxuM2gZe6WFIotPAhbaeYlU4to5cuarF1QrcZ/lwrLaCJl66JBocYZnrNlvm2+MBCTmUymPrYZVbjdlr/BxlMjmNmNI3SAAAAAElFTkSuQmCC', | |
} | |
]); | |
}, | |
}; | |
</script> | |
<style scoped> | |
.container { | |
width: 1000px; | |
height: 600px; | |
} | |
</style> |
common/UserTask.js
import { RectNode, RectNodeModel, h } from "@logicflow/core"; | |
class UserTaskView extends RectNode { | |
getLabelShape() { | |
const { model } = this.props; | |
const { x, y, width, height } = model; | |
const style = model.getNodeStyle(); | |
return h( | |
"svg", | |
{ | |
x: x - width / 2 + 5, | |
y: y - height / 2 + 5, | |
width: 25, | |
height: 25, | |
viewBox: "0 0 1274 1024" | |
}, | |
[ | |
h("path", { | |
fill: style.stroke, | |
d: | |
"M690.366075 350.568358c0-98.876614-79.937349-179.048571-178.558027-179.048571-98.59935 0-178.515371 80.150629-178.515371 179.048571 0 98.833958 79.916021 178.963259 178.515371 178.963259C610.428726 529.531617 690.366075 449.380988 690.366075 350.568358M376.140632 350.568358c0-75.159877 60.72082-136.072649 135.667416-136.072649 74.989253 0 135.667416 60.912772 135.667416 136.072649 0 75.117221-60.678164 136.029993-135.667416 136.029993C436.861451 486.577022 376.140632 425.664251 376.140632 350.568358M197.284012 762.923936 197.284012 778.472049l15.526785 0 291.255186 0.127968L819.784387 778.472049l15.569441 0 0-15.548113c0-139.783721-136.413897-285.581938-311.026243-273.275681-10.002833 0.703824-24.740482 9.128385-34.658002 9.938849-8.573857 0.74648 13.692577 8.232609 14.396401 16.827793 9.021745-0.789136 6.313088 13.095393 15.505457 13.095393 150.597017 0 263.14488 103.07823 263.14488 224.62651l15.441473-15.590769-285.816546-0.042656-278.991585 1.81288 15.526785 15.612097c0-82.752645 75.095893-152.70849 136.861785-191.824044 7.25152-4.58552 8.659169-17.659585 4.862784-22.906273-6.846288-9.426977-19.877697-8.701825-28.046322-6.014496C285.262018 560.521203 197.284012 667.758394 197.284012 762.923936" | |
}), | |
h("path", { | |
fill: style.stroke, | |
d: | |
"M512.31992 1.535616c-282.766642 0-512.021328 228.89211-512.021328 511.210864 0 282.46805 229.254686 511.25352 512.021328 511.25352 117.431975 0 228.828126-39.606098 318.810964-111.204199 10.791969-8.488545 12.540865-24.22861 3.988336-34.99925-8.616513-10.770641-24.356578-12.540865-35.127218-3.94568-81.174373 64.538532-181.586603 100.241606-287.650754 100.241606-255.210864 0-462.028493-206.561693-462.028493-461.367325 0-254.762976 206.817629-461.303341 462.028493-461.303341 255.210864 0 462.092477 206.561693 462.092477 461.303341 0 87.380821-24.33525 171.093227-69.614596 243.651087-7.272848 11.645089-3.668416 27.086562 8.040657 34.35941 11.709073 7.272848 27.10789 3.62576 34.402066-7.976672 50.184787-80.406565 77.143381-173.247355 77.143381-270.055153C1024.383904 230.427726 795.10789 1.535616 512.31992 1.535616z" | |
}) | |
] | |
); | |
} | |
getShape() { | |
const { model } = this.props; | |
const { x, y, width, height, radius } = model; | |
const style = model.getNodeStyle(); | |
return h("g", {}, [ | |
h("rect", { | |
...style, | |
x: x - width / 2, | |
y: y - height / 2, | |
rx: radius, | |
ry: radius, | |
width, | |
height | |
}), | |
this.getLabelShape() | |
]); | |
} | |
} | |
class UserTaskModel extends RectNodeModel { | |
setAttributes() { | |
this.width = 120; | |
this.height = 80; | |
} | |
getTextStyle() { | |
const style = super.getTextStyle(); | |
style.fontSize = 12; | |
const properties = this.properties; | |
style.color = properties.disabled ? "red" : "rgb(24, 125, 255)"; | |
return style; | |
} | |
getNodeStyle() { | |
const style = super.getNodeStyle(); | |
const properties = this.properties; | |
if (properties.disabled) { | |
style.stroke = "red"; | |
} else { | |
style.stroke = "rgb(24, 125, 255)"; | |
} | |
return style; | |
} | |
getAnchorStyle() { | |
const style = super.getAnchorStyle(); | |
style.stroke = "rgb(24, 125, 255)"; | |
style.r = 3; | |
style.hover.r = 8; | |
style.hover.fill = "rgb(24, 125, 255)"; | |
style.hover.stroke = "rgb(24, 125, 255)"; | |
return style; | |
} | |
getAnchorLineStyle() { | |
const style = super.getAnchorLineStyle(); | |
style.stroke = "rgb(24, 125, 255)"; | |
return style; | |
} | |
getOutlineStyle() { | |
const style = super.getOutlineStyle(); | |
style.stroke = "red"; | |
style.hover.stroke = "red"; | |
return style; | |
} | |
} | |
export default { | |
type: "UserTask", | |
view: UserTaskView, | |
model: UserTaskModel | |
}; |