起步
logic-flow
是一个开发流程图的库搜索引擎有可能搜到的是旧版官方文档,啪的一下点进去,很快啊,照着文档一顿搞,结果各种不生效,去github一看,哎不是最新文档,去骗去偷袭我一个练习时长两年半的前端练习生
新旧版文档内容变更比较大,旧版文档的一些代码思路还是值得参考的,新版文档中可能就没有这些内容
旧版官方文档 https://07.logic-flow.cn/
用法
安装
安装核心库和插件库
sh
npm i @logicflow/core @logicflow/extension -s
npm i @logicflow/core @logicflow/extension -s
安装完导入js
和css
js
import { LogicFlow } from "@logicflow/core"
import "@logicflow/core/dist/style/index.css"
import { LogicFlow } from "@logicflow/core"
import "@logicflow/core/dist/style/index.css"
创建容器
在页面中指定一个html元素
作为绘图的容器,又称画布
,比如一个 div
标签
html
<div id="container"></div>
<div id="container"></div>
准备数据
通过 JSON
的数据格式,来让 LogicFlow
渲染。该数据中需要有 nodes
(节点) 和 edges
(边) 字段,分别用数组表示:
实际开发中,用户自己创建一个流程图,前端使用LogicFlow导出如下数据格式流程图数据,保存至后端数据库,下次请求再获取并渲染流程图
js
const data = {
// 节点
nodes: [
{
id: 21,
type: 'rect',
x: 100,
y: 200,
text: {
value: '矩形节点',
x: 100,
y: 200,
},
},
{
id: 50,
type: 'circle',
x: 300,
y: 400,
text: {
value: '圆形节点',
x: 300,
y: 400,
},
},
],
// 边
edges:[
{
type: 'polyline',
sourceNodeId: 50,
targetNodeId: 21,
}
]
}
const data = {
// 节点
nodes: [
{
id: 21,
type: 'rect',
x: 100,
y: 200,
text: {
value: '矩形节点',
x: 100,
y: 200,
},
},
{
id: 50,
type: 'circle',
x: 300,
y: 400,
text: {
value: '圆形节点',
x: 300,
y: 400,
},
},
],
// 边
edges:[
{
type: 'polyline',
sourceNodeId: 50,
targetNodeId: 21,
}
]
}
渲染画布
创建一个 LogicFlow
的实例,此时可以传入一些参数来控制画布,比如画布的大小,最后渲染数据
js
const lf = new LogicFlow({
container: document.querySelector('#container'),
width: 700,
height: 600
})
const lf = new LogicFlow({
container: document.querySelector('#container'),
width: 700,
height: 600
})
通过刚才创建的实例数据渲染到画布上
js
lf.render(data)
lf.render(data)
vue完整示例代码
vue
<script setup lang="ts">
import { LogicFlow } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { onMounted } from 'vue'
const data = {
// 节点
nodes: [
{
id: 21,
type: 'rect',
x: 100,
y: 200,
text: {
value: '矩形节点',
x: 100,
y: 200
}
},
{
id: 50,
type: 'circle',
x: 300,
y: 400,
text: {
value: '圆形节点',
x: 300,
y: 400
}
}
],
// 边
edges: [
{
type: 'polyline',
sourceNodeId: 50,
targetNodeId: 21
}
]
}
onMounted(() => {
const lf = new LogicFlow({
container: document.querySelector('#container') as HTMLElement,
width: 700,
height: 600
})
lf.render(data)
})
</script>
<template>
<div id="container"></div>
</template>
<style scoped></style>
<script setup lang="ts">
import { LogicFlow } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { onMounted } from 'vue'
const data = {
// 节点
nodes: [
{
id: 21,
type: 'rect',
x: 100,
y: 200,
text: {
value: '矩形节点',
x: 100,
y: 200
}
},
{
id: 50,
type: 'circle',
x: 300,
y: 400,
text: {
value: '圆形节点',
x: 300,
y: 400
}
}
],
// 边
edges: [
{
type: 'polyline',
sourceNodeId: 50,
targetNodeId: 21
}
]
}
onMounted(() => {
const lf = new LogicFlow({
container: document.querySelector('#container') as HTMLElement,
width: 700,
height: 600
})
lf.render(data)
})
</script>
<template>
<div id="container"></div>
</template>
<style scoped></style>
网格配置
https://docs.logic-flow.cn/docs/#/zh/api/logicFlowApi?id=grid
网格,若设为false
不开启网格,则为 1px 移动单位,不绘制网格背景,若设置为true
开启则默认为 20px 点状网格
false | Object,默认 false
js
const lf = new LogicFlow({
container: document.querySelector('#container') as HTMLElement,
width: 700,
height: 600,
grid: true
})
const lf = new LogicFlow({
container: document.querySelector('#container') as HTMLElement,
width: 700,
height: 600,
grid: true
})
画布设置
画布宽高
如果不设置画布宽高,默认是容器的宽高
html
<div id="container"></div>
<div id="container"></div>
css
#container {
width: 100%;
height: 100%;
}
#container {
width: 100%;
height: 100%;
}
设置画布固定宽高
js
const lf = new LogicFlow({
container: document.querySelector("#container"),
width: 700,
height: 600,
})
const lf = new LogicFlow({
container: document.querySelector("#container"),
width: 700,
height: 600,
})
主题
- stroke 边框颜色
- stroke-dasharray 边框间隔图案
- stroke-width 边框宽度
- fill 图形元素内部的颜色
- fill-opacity 填色的不透明度或当前对象的内容物的不透明度
- font-size 文本字体大小
- color 文本颜色
setTheme设置主题
js
lf.setTheme({
nodeText: {
color: "#ffffff",
overflowMode: "autoWrap",
fontSize: 15
},
edgeText: {
textWidth: 50,
overflowMode: "autoWrap",
fontSize: 12,
background: {
fillOpacity: 0
}
}
})
lf.setTheme({
nodeText: {
color: "#ffffff",
overflowMode: "autoWrap",
fontSize: 15
},
edgeText: {
textWidth: 50,
overflowMode: "autoWrap",
fontSize: 12,
background: {
fillOpacity: 0
}
}
})
拖拽菜单
https://docs.logic-flow.cn/docs/#/zh/guide/extension/component-dnd-panel
vue示例
vite+vue3
vue
<script setup lang="ts">
import { LogicFlow } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { Control, Menu, DndPanel, SelectionSelect, Snapshot } from '@logicflow/extension'
import '@logicflow/extension/lib/style/index.css'
LogicFlow.use(DndPanel)
import { onMounted } from 'vue'
import one from './node/one'
import two from './node/two'
import three from './node/three'
import four from './node/four'
import five from './node/five'
import six from './node/six'
const registerCustomElement = (lf) => {
lf.register(one)
lf.register(two)
lf.register(three)
lf.register(four)
lf.register(five)
lf.register(six)
}
const data = {
// 节点
nodes: [
{
id: 1,
type: 'image-one',
x: 300,
y: 200,
text: '地调一平面'
},
{
id: 2,
type: 'image-two',
x: 300,
y: 300,
text: '一平面路由器'
},
{
id: 3,
type: 'image-three',
x: 500,
y: 600,
text: '一平面一区纵向'
},
{
id: 4,
type: 'image-four',
x: 300,
y: 600,
text: '一平面一区交换机'
}
],
// 边
edges: [
{
type: 'polyline',
sourceNodeId: 1,
targetNodeId: 2
}
]
}
onMounted(() => {
const lf = new LogicFlow({
container: document.querySelector('#container') as HTMLElement,
width: 1300,
height: 900,
grid: true
})
lf.extension.dndPanel.setPatternItems([
{
label: '选区',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=',
callback: () => {
lf.extension.selectionSelect.openSelectionSelect()
lf.once('selection:selected', () => {
lf.extension.selectionSelect.closeSelectionSelect()
})
}
},
{
type: 'image-one',
text: '地调一平面',
label: '地调一平面',
className: 'icon',
icon: new URL(`/src/assets/images/1.png`, import.meta.url).href
},
{
type: 'image-two',
text: '一平面路由器',
label: '一平面路由器',
className: 'icon',
icon: new URL(`/src/assets/images/2.png`, import.meta.url).href
},
{
type: 'image-three',
text: '一平面一区纵向',
label: '一平面一区纵向',
className: 'icon',
icon: new URL(`/src/assets/images/3.png`, import.meta.url).href
},
{
type: 'image-four',
text: '一平面一区交换机',
label: '一平面一区交换机',
className: 'icon',
icon: new URL(`/src/assets/images/4.png`, import.meta.url).href
}
])
registerCustomElement(lf)
lf.render(data)
})
</script>
<script setup lang="ts">
import { LogicFlow } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { Control, Menu, DndPanel, SelectionSelect, Snapshot } from '@logicflow/extension'
import '@logicflow/extension/lib/style/index.css'
LogicFlow.use(DndPanel)
import { onMounted } from 'vue'
import one from './node/one'
import two from './node/two'
import three from './node/three'
import four from './node/four'
import five from './node/five'
import six from './node/six'
const registerCustomElement = (lf) => {
lf.register(one)
lf.register(two)
lf.register(three)
lf.register(four)
lf.register(five)
lf.register(six)
}
const data = {
// 节点
nodes: [
{
id: 1,
type: 'image-one',
x: 300,
y: 200,
text: '地调一平面'
},
{
id: 2,
type: 'image-two',
x: 300,
y: 300,
text: '一平面路由器'
},
{
id: 3,
type: 'image-three',
x: 500,
y: 600,
text: '一平面一区纵向'
},
{
id: 4,
type: 'image-four',
x: 300,
y: 600,
text: '一平面一区交换机'
}
],
// 边
edges: [
{
type: 'polyline',
sourceNodeId: 1,
targetNodeId: 2
}
]
}
onMounted(() => {
const lf = new LogicFlow({
container: document.querySelector('#container') as HTMLElement,
width: 1300,
height: 900,
grid: true
})
lf.extension.dndPanel.setPatternItems([
{
label: '选区',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=',
callback: () => {
lf.extension.selectionSelect.openSelectionSelect()
lf.once('selection:selected', () => {
lf.extension.selectionSelect.closeSelectionSelect()
})
}
},
{
type: 'image-one',
text: '地调一平面',
label: '地调一平面',
className: 'icon',
icon: new URL(`/src/assets/images/1.png`, import.meta.url).href
},
{
type: 'image-two',
text: '一平面路由器',
label: '一平面路由器',
className: 'icon',
icon: new URL(`/src/assets/images/2.png`, import.meta.url).href
},
{
type: 'image-three',
text: '一平面一区纵向',
label: '一平面一区纵向',
className: 'icon',
icon: new URL(`/src/assets/images/3.png`, import.meta.url).href
},
{
type: 'image-four',
text: '一平面一区交换机',
label: '一平面一区交换机',
className: 'icon',
icon: new URL(`/src/assets/images/4.png`, import.meta.url).href
}
])
registerCustomElement(lf)
lf.render(data)
})
</script>