From fc72df95741a9c23c99cfbb6d3d136346c291649 Mon Sep 17 00:00:00 2001 From: boyongjiong Date: Mon, 13 May 2024 20:29:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=80=E5=8F=91=20feature-examples?= =?UTF-8?q?=20=E4=B8=AD=20BPMN=20=E6=8F=92=E4=BB=B6=20demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/engine-browser-examples/src/main.tsx | 37 -- .../src/pages/core/BasicNode.tsx | 128 ------- .../src/pages/core/RectNode.tsx | 324 ------------------ .../src/pages/core/components/CustomRect.ts | 73 ---- .../src/pages/extension/Control.tsx | 124 ------- .../src/pages/extension/DndPanel.tsx | 114 ------ .../src/pages/extension/Menu.tsx | 124 ------- .../src/routes/root.tsx | 19 - examples/feature-examples/.umirc.ts | 5 + .../src/assets/bpmn/export.png | Bin 0 -> 2783 bytes .../src/assets/bpmn/image.png | Bin 0 -> 2919 bytes .../src/assets/bpmn/upload.png | Bin 0 -> 2784 bytes .../src/pages/extensions/BPMN/bpmn.json | 255 ++++++++++++++ .../src/pages/extensions/BPMN/diagram.xml | 92 +++++ .../src/pages/extensions/BPMN/index.less | 44 +++ .../src/pages/extensions/BPMN/index.tsx | 297 ++++++++++++++++ .../src/pages/extensions/BPMN/svgIcons.ts | 23 ++ .../src/pages/extensions/BPMN/tips.ts | 85 +++++ .../src/pages/extensions/BPMN/util.ts | 14 + .../src/pages/extensions/DndPanel/index.less | 6 + packages/core/src/LogicFlow.tsx | 2 +- packages/core/src/tool/TextEditTool.tsx | 4 +- .../src/components/dnd-panel/index.ts | 5 +- 23 files changed, 827 insertions(+), 948 deletions(-) delete mode 100644 examples/engine-browser-examples/src/pages/core/BasicNode.tsx delete mode 100644 examples/engine-browser-examples/src/pages/core/RectNode.tsx delete mode 100644 examples/engine-browser-examples/src/pages/core/components/CustomRect.ts delete mode 100644 examples/engine-browser-examples/src/pages/extension/Control.tsx delete mode 100644 examples/engine-browser-examples/src/pages/extension/DndPanel.tsx delete mode 100644 examples/engine-browser-examples/src/pages/extension/Menu.tsx create mode 100644 examples/feature-examples/src/assets/bpmn/export.png create mode 100644 examples/feature-examples/src/assets/bpmn/image.png create mode 100644 examples/feature-examples/src/assets/bpmn/upload.png create mode 100644 examples/feature-examples/src/pages/extensions/BPMN/bpmn.json create mode 100644 examples/feature-examples/src/pages/extensions/BPMN/diagram.xml create mode 100644 examples/feature-examples/src/pages/extensions/BPMN/index.less create mode 100644 examples/feature-examples/src/pages/extensions/BPMN/index.tsx create mode 100644 examples/feature-examples/src/pages/extensions/BPMN/svgIcons.ts create mode 100644 examples/feature-examples/src/pages/extensions/BPMN/tips.ts create mode 100644 examples/feature-examples/src/pages/extensions/BPMN/util.ts diff --git a/examples/engine-browser-examples/src/main.tsx b/examples/engine-browser-examples/src/main.tsx index a58c6b8d7..38b97d8c5 100755 --- a/examples/engine-browser-examples/src/main.tsx +++ b/examples/engine-browser-examples/src/main.tsx @@ -6,16 +6,9 @@ import Root from './routes/root' import ErrorPage from './pages/ErrorPage' // 页面组件 -import BasicNode from './pages/core/BasicNode' -import RectNode from './pages/core/RectNode' - import GetStarted from './pages/engine/GetStarted' import Recorder from './pages/engine/Recorder' -import Control from './pages/extension/Control' -import DndPanel from './pages/extension/DndPanel' -import Menu from './pages/extension/Menu' - import './index.css' const router = createBrowserRouter([ @@ -24,19 +17,6 @@ const router = createBrowserRouter([ element: , errorElement: , children: [ - { - path: '/core', - children: [ - { - path: '/core/basic-node', - element: , - }, - { - path: '/core/rect-node', - element: , - }, - ], - }, { path: '/engine', children: [ @@ -50,23 +30,6 @@ const router = createBrowserRouter([ }, ], }, - { - path: '/extension', - children: [ - { - path: '/extension/control', - element: , - }, - { - path: '/extension/dnd-panel', - element: , - }, - { - path: '/extension/menu', - element: , - }, - ], - }, ], }, ]) diff --git a/examples/engine-browser-examples/src/pages/core/BasicNode.tsx b/examples/engine-browser-examples/src/pages/core/BasicNode.tsx deleted file mode 100644 index 88d3dab55..000000000 --- a/examples/engine-browser-examples/src/pages/core/BasicNode.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { useRef, useEffect } from 'react' -import LogicFlow from '@logicflow/core' - -import '@logicflow/core/es/index.css' - -const config: Partial = { - isSilentMode: false, - stopScrollGraph: true, - stopZoomGraph: true, - allowRotation: true, - adjustEdge: true, - style: { - rect: { - rx: 5, - ry: 5, - strokeWidth: 2, - }, - circle: { - fill: '#f5f5f5', - stroke: '#666', - }, - ellipse: { - fill: '#dae8fc', - stroke: '#6c8ebf', - }, - polygon: { - fill: '#d5e8d4', - stroke: '#82b366', - }, - diamond: { - fill: '#ffe6cc', - stroke: '#d79b00', - }, - text: { - color: '#b85450', - fontSize: 12, - }, - }, -} - -const data = { - nodes: [ - { - id: '1', - type: 'rect', - x: 100, - y: 100, - text: '矩形', - }, - { - id: '2', - type: 'circle', - x: 300, - y: 100, - text: '圆形', - }, - { - id: '3', - type: 'ellipse', - x: 500, - y: 100, - text: '椭圆', - }, - { - id: '4', - type: 'polygon', - x: 100, - y: 250, - text: '多边形', - }, - { - id: '5', - type: 'diamond', - x: 300, - y: 250, - text: '菱形', - }, - { - id: '6', - type: 'text', - x: 500, - y: 250, - text: '纯文本节点', - }, - { - id: '7', - type: 'html', - x: 100, - y: 400, - text: 'html节点', - }, - ], -} - -export default function BasicNode() { - const lfRef = useRef() - const containerRef = useRef(null) - useEffect(() => { - if (!lfRef.current) { - const lf = new LogicFlow({ - ...config, - container: containerRef.current as HTMLElement, - // container: document.querySelector('#graph') as HTMLElement, - grid: { - size: 10, - }, - }) - - lf.render(data) - lfRef.current = lf - console.log(lf.getGraphRawData()) - } - }, []) - - return ( - <> -
Basic Node Demo
-
-
{ - console.log(lfRef.current!.getGraphRawData()) - }} - > - lf.getGraphRawData -
- - ) -} diff --git a/examples/engine-browser-examples/src/pages/core/RectNode.tsx b/examples/engine-browser-examples/src/pages/core/RectNode.tsx deleted file mode 100644 index cfff86c71..000000000 --- a/examples/engine-browser-examples/src/pages/core/RectNode.tsx +++ /dev/null @@ -1,324 +0,0 @@ -import { useRef, useEffect } from 'react' -import LogicFlow from '@logicflow/core' -import CustomRect from './components/CustomRect' - -import '@logicflow/core/es/index.css' - -const config: Partial = { - isSilentMode: false, - stopScrollGraph: true, - stopZoomGraph: true, - style: { - rect: { - width: 100, - height: 50, - rx: 2, - ry: 2, - }, - }, -} - -// const data = { -// nodes: [ -// { -// id: '10', -// type: 'rect', -// x: 150, -// y: 70, -// text: '矩形', -// }, -// { -// id: '20', -// type: 'rect', -// x: 350, -// y: 70, -// text: '矩形', -// }, -// ], -// } - -export default function RectNode() { - const lfRef = useRef() - const containerRef = useRef(null) - useEffect(() => { - if (!lfRef.current) { - const lf = new LogicFlow({ - ...config, - container: containerRef.current as HTMLElement, - // container: document.querySelector('#graph') as HTMLElement, - grid: { - size: 10, - }, - }) - - lf.register(CustomRect) - lf.render({}) - - // row 1 - lf.addNode({ - id: '10', - type: 'customRect', - x: 150, - y: 70, - text: '矩形', - }) - - lf.addNode({ - id: '11', - type: 'customRect', - x: 350, - y: 70, - text: '矩形', - properties: { - style: { - fill: '#efdbff', - stroke: '#9254de', - }, - }, - }) - - lf.addNode({ - id: '12', - type: 'customRect', - x: 550, - y: 70, - text: '矩形', - properties: { - radius: 8, - style: { - fill: '#f8cecc', - stroke: '#b85450', - }, - }, - }) - - lf.addNode({ - id: '13', - type: 'customRect', - x: 730, - y: 70, - text: '矩形', - properties: { - width: 60, - height: 60, - radius: 20, - style: { - fill: '#ffe6cc', - stroke: '#d79b00', - }, - textStyle: { - textAnchor: 'middle', - dominantBaseline: 'middle', - }, - }, - }) - - // row 2 - lf.addNode({ - id: '20', - type: 'customRect', - x: 150, - y: 200, - text: '矩形', - properties: { - refX: -25, - refY: -20, - }, - }) - - lf.addNode({ - id: '21', - type: 'customRect', - x: 350, - y: 200, - text: '矩形', - properties: { - refX: -25, - style: { - fill: '#efdbff', - stroke: '#9254de', - }, - }, - }) - - lf.addNode({ - id: '22', - type: 'customRect', - x: 550, - y: 200, - text: '矩形', - properties: { - radius: 8, - refX: -25, - refY: 20, - style: { - fill: '#f8cecc', - stroke: '#b85450', - }, - }, - }) - - lf.addNode({ - id: '23', - type: 'customRect', - x: 730, - y: 200, - text: '矩形', - properties: { - width: 60, - height: 60, - radius: 20, - refY: -40, - style: { - fill: '#ffe6cc', - stroke: '#d79b00', - }, - textStyle: { - textAnchor: 'middle', - dominantBaseline: 'middle', - }, - }, - }) - - // row 3 - lf.addNode({ - id: '30', - type: 'customRect', - x: 150, - y: 330, - text: '矩形', - properties: { - refY: -20, - }, - }) - - lf.addNode({ - id: '31', - type: 'customRect', - x: 350, - y: 330, - text: '矩形', - properties: { - style: { - fill: '#efdbff', - stroke: '#9254de', - }, - }, - }) - - lf.addNode({ - id: '32', - type: 'customRect', - x: 550, - y: 330, - text: '矩形', - properties: { - radius: 8, - refY: 20, - style: { - fill: '#f8cecc', - stroke: '#b85450', - }, - }, - }) - - lf.addNode({ - id: '33', - type: 'customRect', - x: 730, - y: 330, - text: '矩形', - properties: { - width: 60, - height: 60, - radius: 20, - refX: 48, - style: { - fill: '#ffe6cc', - stroke: '#d79b00', - }, - textStyle: { - textAnchor: 'middle', - dominantBaseline: 'middle', - }, - }, - }) - - // row 4 - lf.addNode({ - id: '40', - type: 'customRect', - x: 150, - y: 460, - text: '矩形', - properties: { - refX: 20, - refY: -20, - }, - }) - - lf.addNode({ - id: '41', - type: 'customRect', - x: 350, - y: 460, - text: '矩形', - properties: { - refX: 20, - style: { - fill: '#efdbff', - stroke: '#9254de', - }, - }, - }) - - lf.addNode({ - id: '42', - type: 'customRect', - x: 550, - y: 460, - text: '矩形', - properties: { - radius: 8, - refX: 20, - refY: 20, - style: { - fill: '#f8cecc', - stroke: '#b85450', - }, - }, - }) - - lf.addNode({ - id: '43', - type: 'customRect', - x: 730, - y: 460, - text: '矩形', - properties: { - width: 60, - height: 60, - radius: 20, - refY: 40, - style: { - fill: '#ffe6cc', - stroke: '#d79b00', - }, - textStyle: { - textAnchor: 'middle', - dominantBaseline: 'middle', - }, - }, - }) - - lfRef.current = lf - } - }, []) - - return ( - <> -
Basic Node Demo
-
- - ) -} diff --git a/examples/engine-browser-examples/src/pages/core/components/CustomRect.ts b/examples/engine-browser-examples/src/pages/core/components/CustomRect.ts deleted file mode 100644 index 59e07c8a4..000000000 --- a/examples/engine-browser-examples/src/pages/core/components/CustomRect.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { LogicFlow, RectNode, RectNodeModel } from '@logicflow/core' -import { cloneDeep } from 'lodash-es' - -export type CustomProperties = { - // 形状属性 - width?: number - height?: number - radius?: number - - // 文字位置属性 - refX?: number - refY?: number - - // 样式属性 - style?: LogicFlow.CommonTheme - textStyle?: LogicFlow.TextNodeTheme -} - -class CustomRectNode extends RectNode {} - -class CustomRectNodeModel extends RectNodeModel { - setAttributes() { - console.log('this.properties', this.properties) - const { width, height, radius } = this.properties as CustomProperties - if (width) { - this.width = width - } - if (height) { - this.height = height - } - if (radius) { - this.radius = radius - } - } - - getTextStyle(): LogicFlow.TextNodeTheme { - // const { x, y, width, height } = this - const { - refX = 0, - refY = 0, - textStyle, - } = this.properties as CustomProperties - const style = super.getTextStyle() - - // 通过 transform 重新设置 text 的位置 - return { - ...style, - ...(cloneDeep(textStyle) || {}), - transform: `matrix(1 0 0 1 ${refX} ${refY})`, - } - } - - getNodeStyle(): LogicFlow.CommonTheme { - const style = super.getNodeStyle() - const { - style: customNodeStyle, - // radius = 0, // 第二种方式,设置圆角 - } = this.properties as CustomProperties - - return { - ...style, - ...(cloneDeep(customNodeStyle) || {}), - // rx: radius, - // ry: radius, - } - } -} - -export default { - type: 'customRect', - view: CustomRectNode, - model: CustomRectNodeModel, -} diff --git a/examples/engine-browser-examples/src/pages/extension/Control.tsx b/examples/engine-browser-examples/src/pages/extension/Control.tsx deleted file mode 100644 index 68a8224a3..000000000 --- a/examples/engine-browser-examples/src/pages/extension/Control.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import LogicFlow from '@logicflow/core' -import { Control } from '@logicflow/extension' - -import { useEffect, useRef } from 'react' - -import '@logicflow/core/es/index.css' -// import '@logicflow/extension/es/index.less' - -const config: Partial = { - isSilentMode: false, - stopScrollGraph: true, - stopZoomGraph: true, - style: { - rect: { - rx: 5, - ry: 5, - strokeWidth: 2, - }, - circle: { - fill: '#f5f5f5', - stroke: '#666', - }, - ellipse: { - fill: '#dae8fc', - stroke: '#6c8ebf', - }, - polygon: { - fill: '#d5e8d4', - stroke: '#82b366', - }, - diamond: { - fill: '#ffe6cc', - stroke: '#d79b00', - }, - text: { - color: '#b85450', - fontSize: 12, - }, - }, -} - -const data = { - nodes: [ - { - id: '1', - type: 'rect', - x: 150, - y: 100, - text: '矩形', - }, - { - id: '2', - type: 'circle', - x: 350, - y: 100, - text: '圆形', - }, - { - id: '3', - type: 'ellipse', - x: 550, - y: 100, - text: '椭圆', - }, - { - id: '4', - type: 'polygon', - x: 150, - y: 250, - text: '多边形', - }, - { - id: '5', - type: 'diamond', - x: 350, - y: 250, - text: '菱形', - }, - { - id: '6', - type: 'text', - x: 550, - y: 250, - text: '纯文本节点', - }, - { - id: '7', - type: 'html', - x: 150, - y: 400, - text: 'html节点', - }, - ], -} - -export default function ControlExtension() { - const lfRef = useRef() - const containerRef = useRef(null) - useEffect(() => { - console.log('Control --->>>', Control.pluginName) - - if (!lfRef.current) { - const lf = new LogicFlow({ - ...config, - container: containerRef.current as HTMLElement, - // container: document.querySelector('#graph') as HTMLElement, - grid: { - size: 10, - }, - plugins: [Control], - }) - - lf.render(data) - lfRef.current = lf - } - }, []) - - return ( - <> -
Extension - Control
-
- - ) -} diff --git a/examples/engine-browser-examples/src/pages/extension/DndPanel.tsx b/examples/engine-browser-examples/src/pages/extension/DndPanel.tsx deleted file mode 100644 index 660be3808..000000000 --- a/examples/engine-browser-examples/src/pages/extension/DndPanel.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import LogicFlow from '@logicflow/core' -import { DndPanel } from '@logicflow/extension' - -import { useEffect, useRef } from 'react' - -import '@logicflow/core/es/index.css' -// import '@logicflow/extension/es/index.less' - -const config: Partial = { - isSilentMode: false, - stopScrollGraph: true, - stopZoomGraph: true, - style: { - rect: { - rx: 5, - ry: 5, - strokeWidth: 2, - }, - circle: { - fill: '#f5f5f5', - stroke: '#666', - }, - ellipse: { - fill: '#dae8fc', - stroke: '#6c8ebf', - }, - polygon: { - fill: '#d5e8d4', - stroke: '#82b366', - }, - diamond: { - fill: '#ffe6cc', - stroke: '#d79b00', - }, - text: { - color: '#b85450', - fontSize: 12, - }, - }, -} - -const data = { - nodes: [ - { - id: '1', - type: 'rect', - x: 150, - y: 100, - text: '矩形', - }, - { - id: '2', - type: 'circle', - x: 350, - y: 100, - text: '圆形', - }, - ], -} - -export default function DndPanelExtension() { - const lfRef = useRef() - const containerRef = useRef(null) - useEffect(() => { - if (!lfRef.current) { - const lf = new LogicFlow({ - ...config, - container: containerRef.current as HTMLElement, - // container: document.querySelector('#graph') as HTMLElement, - grid: { - size: 10, - }, - plugins: [DndPanel], - }) - - lf.render(data) - // lf.extension.dndPanel - lf.setPatternItems([ - { - 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: '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', - }, - ]) - - lfRef.current = lf - } - }, []) - - return ( - <> -
Extension - DndPanel
-
- - ) -} diff --git a/examples/engine-browser-examples/src/pages/extension/Menu.tsx b/examples/engine-browser-examples/src/pages/extension/Menu.tsx deleted file mode 100644 index 4cd84ab44..000000000 --- a/examples/engine-browser-examples/src/pages/extension/Menu.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import LogicFlow from '@logicflow/core' -import { Menu } from '@logicflow/extension' - -import { useEffect, useRef } from 'react' - -import '@logicflow/core/es/index.css' -// import '@logicflow/extension/es/index.less' - -const config: Partial = { - isSilentMode: false, - stopScrollGraph: true, - stopZoomGraph: true, - style: { - rect: { - rx: 5, - ry: 5, - strokeWidth: 2, - }, - circle: { - fill: '#f5f5f5', - stroke: '#666', - }, - ellipse: { - fill: '#dae8fc', - stroke: '#6c8ebf', - }, - polygon: { - fill: '#d5e8d4', - stroke: '#82b366', - }, - diamond: { - fill: '#ffe6cc', - stroke: '#d79b00', - }, - text: { - color: '#b85450', - fontSize: 12, - }, - }, -} - -const data = { - nodes: [ - { - id: '1', - type: 'rect', - x: 150, - y: 100, - text: '矩形', - }, - { - id: '2', - type: 'circle', - x: 350, - y: 100, - text: '圆形', - }, - { - id: '3', - type: 'ellipse', - x: 550, - y: 100, - text: '椭圆', - }, - { - id: '4', - type: 'polygon', - x: 150, - y: 250, - text: '多边形', - }, - { - id: '5', - type: 'diamond', - x: 350, - y: 250, - text: '菱形', - }, - { - id: '6', - type: 'text', - x: 550, - y: 250, - text: '纯文本节点', - }, - { - id: '7', - type: 'html', - x: 150, - y: 400, - text: 'html节点', - }, - ], -} - -export default function MenuExtension() { - const lfRef = useRef() - const containerRef = useRef(null) - useEffect(() => { - console.log('Menu --->>>', Menu) - - if (!lfRef.current) { - const lf = new LogicFlow({ - ...config, - container: containerRef.current as HTMLElement, - // container: document.querySelector('#graph') as HTMLElement, - grid: { - size: 10, - }, - plugins: [Menu], - }) - - lf.render(data) - lfRef.current = lf - } - }, []) - - return ( - <> -
Extension - Menu
-
- - ) -} diff --git a/examples/engine-browser-examples/src/routes/root.tsx b/examples/engine-browser-examples/src/routes/root.tsx index 4a40342d0..24d39b756 100755 --- a/examples/engine-browser-examples/src/routes/root.tsx +++ b/examples/engine-browser-examples/src/routes/root.tsx @@ -23,30 +23,11 @@ export default function Root() { diff --git a/examples/feature-examples/.umirc.ts b/examples/feature-examples/.umirc.ts index 66ce3b25e..8c68c14a0 100644 --- a/examples/feature-examples/.umirc.ts +++ b/examples/feature-examples/.umirc.ts @@ -69,6 +69,11 @@ export default defineConfig({ name: 'DndPanel 插件', component: './extensions/DndPanel', }, + { + path: '/extension/bpmn', + name: 'BPMN 插件', + component: './extensions/BPMN', + }, ], }, ], diff --git a/examples/feature-examples/src/assets/bpmn/export.png b/examples/feature-examples/src/assets/bpmn/export.png new file mode 100644 index 0000000000000000000000000000000000000000..886ba697c08403ffaa155ec8ebaf5eb12c63359b GIT binary patch literal 2783 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 US^Vey+aD`9Wom6wX5@MGKZV``S^xk5 literal 0 HcmV?d00001 diff --git a/examples/feature-examples/src/assets/bpmn/image.png b/examples/feature-examples/src/assets/bpmn/image.png new file mode 100644 index 0000000000000000000000000000000000000000..f1cf768e0907cae32334ef08467105463a2e43e5 GIT binary patch literal 2919 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 RSrGsL002ovPDHLkV1kSEUfloy literal 0 HcmV?d00001 diff --git a/examples/feature-examples/src/assets/bpmn/upload.png b/examples/feature-examples/src/assets/bpmn/upload.png new file mode 100644 index 0000000000000000000000000000000000000000..cdac4ff45e84240fa6293e7a0673cd4cd6c77a52 GIT binary patch literal 2784 zcmcJR`8(8o7so%}F~%4}6T?hJOp#DXZnDf6V=rq+*=DqmeHk+Lv2QU-g(#zhC`7j? zGSVGVv>+6w$XJqPEUD!7JU>1E!1Kd7uj_rzPv^SMb0P4Dhv7rOQeeQ-;8rBTk;k#-S%&R-9Z!VUQ0!LTB z7;&W}WQb!D^5AW96Wqt9oeKGIdAJ(|vt%eHTrnFd!Z?IurQf=2pXM8Cg%-A3%wgDu zsy#6cAIYxycs<7cy{u#Z%8;9=#;j$yRex0L&sL{?N1~{BwzCV{ZgwE`MJ^z}CLjSE z_yojX*EZNs2JA_xiU@up?0-wKQg~;BW?^TdfsIyJ*d=}+45!9=^rt%0QTaaLo(~Ga zn(S&T$wH*dP(zLFU?$<=XRz*7Xw$ENZLKJ;dvfCZXzwA6V`7O0@WbOtSH3Q{mEe%S z+dJNL&uy}zeyYX2D7SR=i<^VrITYy~@*AT@RxRcc!Kv(W>#-++PabY4Av>~*0u19t zW@mi-R^7HY3(CD-+&jOoM|FHz-x(mK5XfygDnC#OdEl%LHE;aX{yOrHm6`O{??TQ@ zQ)+;@c=MEWgXD6geYTB&$JsTUf8Z}Esb+{dx1uG}n*cmKzD;>AHyBvl!hyzb(KBIG zLeOq7uzp67^bP;+6slN;D$-;aWgbKoEd;8zU=WY!?C}Y>%B+bvPI7?4BmaAA)|A;Ob={@(I zzFd9dm{H3fFRz$vGa+@~so}Gi>;Y}MCV~GxH7!6P*%~58wc6}3sL|j?bMDx3(csAJ zn$CBA5-cwzMGVT3k9GXE;a$R!lnjC~E7xN4=#Uwxh@B626uc+EJiMv=;?Hlr)KxS1 z0K^%OrF#8ln8B8tleZfJ=9^Qk%8GFj$~3(l4=X`fZX7PxunP3q{c#f!um-k@>*4;I zG)b^?vr2Qmw-EEC&{&JlbcTUP-X1uNTcd)ztLQaup0uk4On{&r0SIizF03-Nvba3`t4 zkcU-g@m-7#w_~^_d(!B$6C8Smfw@eh$IzGXX+N;+=eO5!nh`pJ#Uhc;J}7f7cV&WM46fh zWf<8eiL50WJK=;OZo)E7hbliLkxcMU;=iK==Duu)rSW-37+=(0+!r%#5fh$u4?3!JxDB%~?D8E+|fb=M}!tt*t z_Nu^dZmdHzVI`_Io3%TF{JtqDvaA5IHp)gjj|h1{q*58M*WlQr5iECciN$itqzOn zpslMwM}u@V?cUu&PhRZL8_^4+9~Q%xz8z6ULnk3i2y@KyJM! zIMS0JjlIMw6F>Jw$8uC#CuS10V`MXHH&~5pU^Q>Nkh3YgTC^7yUj_0*N%)PayTx6L zHmq5Q)~guRneD%;v(B?dT!@c_8E@*X$TkJfnRZNTZ#E7^j!6NR(NC9$E;><988rmD zb-cG!;JLOQwu)_DD0BvF&rm!vYhF7sIRztl(hMISSDn$Z%4@LulnE!eeLANgnbCwtcy$fT~ouvB{5mR{Mq`{ zvq@ZtCrQ!E+z!}#*f3qAwwCErA&UbJ3P9ak#nyNVpWy|=#pbUsbhSUQ=d9}*Z5*dVh4%$|Q#FpiD*$yeNiPioVf&F}FFgDHz*s zp@AeZ7V)KdtAiL*C0XKGb2PJ@P{;cbqDF3riTL2b>-Iw(6a|Ib(v;&-xBDc4V^5wK zG#J6?#y3;1;46dl58e&{wTD_Qd!259hnUsiLuC}o4Zx8grjPt{0rCpdFNt6_k9Jc4 z0U~$09I!hfIs?e%wA&6~AFGzwsDJGLw&%(9 zk;hNV?z=LMZn-I;-rIv09gZ#?Yd!(aA0Ewzu`*<)`o~J=%W{hg^MQaMjxD4y`Nkhllpzp+aSN*KW@||W%=jET zhb5QCSGr&Lie=A;*^fL0OrOli6YhX>IQ4FI03iQuLR3)$+=6xoCvCtUzIF2|4lKO# zsI1xrZ2j$eUy1<6q + + + + Flow_17mk55x + + + Flow_00um71v + Flow_1iy6wvy + Flow_05w5m1i + + + + + + Flow_091o1xz + + + + Flow_1iy6wvy + Flow_091o1xz + + + Flow_17mk55x + Flow_00um71v + + + + Flow_05w5m1i + Flow_1hzglvd + + + Flow_1hzglvd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/feature-examples/src/pages/extensions/BPMN/index.less b/examples/feature-examples/src/pages/extensions/BPMN/index.less new file mode 100644 index 000000000..e916b4b2a --- /dev/null +++ b/examples/feature-examples/src/pages/extensions/BPMN/index.less @@ -0,0 +1,44 @@ +.viewport { + position: relative; + height: 70vh; + overflow: hidden; +} + +:global { + .graph-io { + position: absolute; + right: 15px; + bottom: 10px; + z-index: 9999; + display: flex; + padding: 10px; + background: rgb(255 255 255 / 80%); + border-radius: 5px; + box-shadow: 0 1px 4px rgb(0 0 0 / 30%); + } + + .graph-io a { + margin: 0 5px; + } + + .graph-io a img { + height: 24px; + } + + .custom-minimap { + background: url("data:image/png;base64,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"); + } + + .upload { + position: absolute; + top: 0; + left: 0; + z-index: 99; + cursor: pointer; + opacity: 0; + } + + .upload::-webkit-file-upload-button { + cursor: pointer; + } +} diff --git a/examples/feature-examples/src/pages/extensions/BPMN/index.tsx b/examples/feature-examples/src/pages/extensions/BPMN/index.tsx new file mode 100644 index 000000000..e79a8faca --- /dev/null +++ b/examples/feature-examples/src/pages/extensions/BPMN/index.tsx @@ -0,0 +1,297 @@ +import LogicFlow from '@logicflow/core' +import { + AutoLayout, + BpmnElement, + BpmnXmlAdapter, + ContextMenu, + Control, + DndPanel, + ShapeItem, + FlowPath, + Menu, + Group, + MiniMap, + SelectionSelect, + Snapshot, +} from '@logicflow/extension' + +import { Button, Card, Divider, Flex } from 'antd' +import { useEffect, useRef } from 'react' + +import { + startEventIcon, + endEventIcon, + userTaskIcon, + serviceTaskIcon, + exclusiveGatewayIcon, + groupIcon, + selectionIcon, + deleteMenuIcon, +} from './svgIcons' + +import '@logicflow/core/es/index.css' +import '@logicflow/extension/es/index.css' +import styles from './index.less' +import NodeData = LogicFlow.NodeData +import GraphConfigData = LogicFlow.GraphConfigData + +const config: Partial = { + edgeTextDraggable: true, + nodeTextDraggable: true, + // adjustNodePosition: false, + // stopMoveGraph: true, + // multipleSelectedKey: 'meta', // alt, shift + hideAnchors: false, + plugins: [ + BpmnElement, + MiniMap, + FlowPath, + AutoLayout, + DndPanel, + Menu, + ContextMenu, + Group, + Control, + BpmnXmlAdapter, + Snapshot, + SelectionSelect, + ], + // isSilentMode: true, + grid: { + type: 'dot', + size: 20, + }, + keyboard: { + enabled: true, + }, + snapline: true, +} + +const menuConfig: Record = { + nodeMenu: [ + { + text: '分享', + callback() { + console.log('分享成功!') + }, + }, + { + text: '复制', + callback() { + console.log('分享成功!') + }, + }, + { + text: '修改', + callback() { + console.log('分享成功!') + }, + }, + ], + graphMenu: [ + { + text: '分111享', + callback() { + console.log('分享成功22!') + }, + }, + ], +} + +// @ts-ignore +const getDndPanelConfig = (lf: LogicFlow): ShapeItem[] => [ + { + label: '选区', + icon: selectionIcon, + callback: () => { + lf.openSelectionSelect() + lf.once('selection:selected', () => { + lf.closeSelectionSelect() + }) + }, + }, + { + type: 'bpmn:startEvent', + text: '开始', + label: '开始', + icon: startEventIcon, + }, + { + type: 'bpmn:userTask', + label: '用户任务', + icon: userTaskIcon, + properties: { + actived: true, + }, + }, + { + type: 'bpmn:serviceTask', + label: '系统任务', + icon: serviceTaskIcon, + cls: 'import_icon', + }, + { + type: 'bpmn:exclusiveGateway', + label: '条件判断', + icon: exclusiveGatewayIcon, + }, + { + type: 'bpmn:endEvent', + label: '结束', + icon: endEventIcon, + }, + { + type: 'group', + label: '分组', + icon: groupIcon, + }, +] + +export default function BPMNExtension() { + const lfRef = useRef() + const containerRef = useRef(null) + + const renderXml = (xml: GraphConfigData) => { + const lf = lfRef.current + if (!lf) { + return + } + lf.renderByXml(xml) + } + + useEffect(() => { + if (!lfRef.current) { + const lf = new LogicFlow({ + ...config, + container: containerRef.current as HTMLElement, + }) + + lf.setMenuConfig(menuConfig) + + const commonMenuConfig = { + icon: deleteMenuIcon, + callback: (data: NodeData) => { + lf.deleteElement(data.id) + lf.hideContextMenu() + }, + } + lf.setContextMenuItems(commonMenuConfig) + // TODO: 待确认具体功能 + // lf.setContextMenuByType('bpmn:serviceTask', [ + // userConfig, + // serviceConfig, + // exclusiveGatewayConfig, + // endConfig, + // groupConfig, + // ]); + + const dndPanelConfig = getDndPanelConfig(lf) + lf.setPatternItems(dndPanelConfig) + + // TODO: 解决 lf extension 插件注册之后,类型仍然是 Extension 的问题,需要注册后定义对应类型,以方便访问其属性 or 方法 + const { control, miniMap } = lf.extension + + ;(control as Control).addItem({ + iconClass: 'custom-minimap', + title: '', + text: '导航', + onMouseEnter: (lf: LogicFlow, ev: MouseEvent) => { + const position = lf.getPointByClient(ev.x, ev.y) + ;(miniMap as MiniMap).show( + position.domOverlayPosition.x - 120, + position.domOverlayPosition.y + 35, + ) + }, + onClick: (lf: LogicFlow, ev: MouseEvent) => { + // console.log(MiniMap, ev); + const position = lf.getPointByClient(ev.x, ev.y) + // console.log(position); + ;(miniMap as MiniMap).show( + position.domOverlayPosition.x - 120, + position.domOverlayPosition.y + 35, + ) + }, + }) + + // 获取渲染数据 + let lfData: GraphConfigData + + const sessionStorageData = window.sessionStorage.getItem('lf-data') + if (sessionStorageData) { + lfData = JSON.parse(sessionStorageData) + renderXml(lfData) + } else { + const lfJsonData = window.sessionStorage.getItem('lf-json-data') + if (!lfJsonData) { + lfData = { + nodes: [], + edges: [], + } + } else { + lfData = JSON.parse(lfJsonData) + } + lf.render(lfData as GraphConfigData) + } + const pathes = window.sessionStorage.getItem('lf-pathes') + if (pathes) { + lf.setRawPathes(JSON.parse(pathes)) + } + + lfRef.current = lf + } + }, []) + + return ( + +

兼容BPMN官方DEMO,此处仅实现了bpmn中的一部分节点

+

此页面绘制的图可以在BPMN官方DEMO中正常使用

+

+ 点击左下角下载xml,将文件上传到{' '} + + https://demo.bpmn.io/ + + 即可使用。 +

+ + + + + + + + + + +
+ +
+ ) +} diff --git a/examples/feature-examples/src/pages/extensions/BPMN/svgIcons.ts b/examples/feature-examples/src/pages/extensions/BPMN/svgIcons.ts new file mode 100644 index 000000000..6982fb5b5 --- /dev/null +++ b/examples/feature-examples/src/pages/extensions/BPMN/svgIcons.ts @@ -0,0 +1,23 @@ +export const startEventIcon: string = + '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==' + +export const endEventIcon: string = + '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' + +export const userTaskIcon: string = + '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==' + +export const serviceTaskIcon: string = + '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==' + +export const exclusiveGatewayIcon: string = + '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=' + +export const groupIcon: string = + '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' + +export const selectionIcon: string = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=' + +export const deleteMenuIcon = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAVhJREFUOE/VlLFKA0EQhmewEazshVjGJlgKWkSLNAGdveMqEayt4hMY9AXyCIKVhuy/TSwCFnZ2Jp1vIRaWZmTCBc6LF86ooNvcz+38383tzw7TnCUi68xcyZao6ksIYVhk46KNFPZIRKNcjX2k473vfOadB6wzcxtAPWsUEWHmVv79tIadc4GIDub9etk9Zj4t7LAsJF/3ARhFUcsKis4nbxaRTWY+BjDx2coD2ylw8ozjuNrr9Z5Mm3mabhRFW977BxGZOedCoHMuIaITALvOuT0i6gCoxXFcU9Vb7/3aIsAbABacAe9MG3A8Ho9MLwI8BCC/BTwHsJN2aJ1Xv9vh/wL+nVCuACz/WMqqehRC2Degql6EELbTlK8BbHwpZbtuSZIsdbvdN9ONRmNlMBi8mm42m6v9fv+5LLCiqpdlpo2q2nBw2dk4c5dV9SyF3ZeBEtEwO23eAUh+SIoWcATkAAAAAElFTkSuQmCC' diff --git a/examples/feature-examples/src/pages/extensions/BPMN/tips.ts b/examples/feature-examples/src/pages/extensions/BPMN/tips.ts new file mode 100644 index 000000000..d48555258 --- /dev/null +++ b/examples/feature-examples/src/pages/extensions/BPMN/tips.ts @@ -0,0 +1,85 @@ +import LogicFlow from '@logicflow/core' +import NodeData = LogicFlow.NodeData + +const nodeWidth = 100 +const nodeHeight = 80 + +export interface ITipsProps { + lf: LogicFlow +} + +export class Tips { + static pluginName = 'tips' + + private lf: LogicFlow + tipsWrap: HTMLDivElement + container?: HTMLElement + isDragging: boolean = false + currentData: any + isCurrentLeaveId?: string + + constructor({ lf }: ITipsProps) { + this.lf = lf + const tipsWrap = document.createElement('div') + tipsWrap.className = 'custom-tips' + this.tipsWrap = tipsWrap + } + + render(lf: LogicFlow, container: HTMLElement) { + this.container = container + this.container.appendChild(this.tipsWrap) + + // TODO: 解决 lf 事件监听 callback 函数的类型定义问题(是否需要统一,比如 {data: NodeData | EdgeData | undefined, ev: MouseEvent | xxxDOMEvent}) + this.lf.on('node:mouseenter', ({ data }: any) => { + const model = this.lf.graphModel.getNodeModelById(data.id) + // 没有model可以认为是fakernode, 也就是正在外部拖入的节点。 + if (!model) return + this.showTip(data) + }) + this.lf.on('node:mouseleave', ({ data }: any) => { + const model = this.lf.graphModel.getNodeModelById(data.id) + // 没有model可以认为是fakernode, 也就是正在外部拖入的节点。 + if (!model) return + this.isCurrentLeaveId = data.id + setTimeout(() => { + if (this.isCurrentLeaveId === data.id) { + this.hideTips() + } + }, 200) + }) + this.lf.on('node:dragstart', () => { + this.isDragging = true + this.hideTips() + }) + this.lf.on('node:drop', ({ data }: any) => { + this.isDragging = false + this.showTip(data) + }) + this.tipsWrap.addEventListener('click', () => { + this.currentData && lf.graphModel.deleteNode(this.currentData.id) + this.hideTips() + }) + this.tipsWrap.addEventListener('mouseenter', () => { + this.isCurrentLeaveId = undefined + }) + this.tipsWrap.addEventListener('mouseleave', () => { + this.hideTips() + }) + } + + showTip(data: NodeData) { + if (this.isDragging) return + this.currentData = data + const [x, y] = this.lf.graphModel.transformModel.CanvasPointToHtmlPoint([ + data.x + nodeWidth / 2 + 4, + data.y - nodeHeight / 2, + ]) + this.tipsWrap.style.display = 'block' + this.tipsWrap.style.top = `${y}px` + this.tipsWrap.style.left = `${x}px` + } + + hideTips() { + this.tipsWrap.style.display = 'none' + } +} diff --git a/examples/feature-examples/src/pages/extensions/BPMN/util.ts b/examples/feature-examples/src/pages/extensions/BPMN/util.ts new file mode 100644 index 000000000..9221b4f16 --- /dev/null +++ b/examples/feature-examples/src/pages/extensions/BPMN/util.ts @@ -0,0 +1,14 @@ +export function download(filename: string, text: string) { + const element = document.createElement('a') + element.setAttribute( + 'href', + 'data:text/plain;charset=utf-8,' + encodeURIComponent(text), + ) + element.setAttribute('download', filename) + + element.style.display = 'none' + document.body.appendChild(element) + + element.click() + document.body.removeChild(element) +} diff --git a/examples/feature-examples/src/pages/extensions/DndPanel/index.less b/examples/feature-examples/src/pages/extensions/DndPanel/index.less index 8eb833cff..3620ce9ce 100644 --- a/examples/feature-examples/src/pages/extensions/DndPanel/index.less +++ b/examples/feature-examples/src/pages/extensions/DndPanel/index.less @@ -2,4 +2,10 @@ position: relative; height: 80vh; overflow: hidden; + + :global { + .lf-dnd-shape { + background-size: contain; + } + } } diff --git a/packages/core/src/LogicFlow.tsx b/packages/core/src/LogicFlow.tsx index cc66b0766..c363b19d8 100644 --- a/packages/core/src/LogicFlow.tsx +++ b/packages/core/src/LogicFlow.tsx @@ -1697,7 +1697,7 @@ export namespace LogicFlow { export interface Extension { readonly pluginName?: string // 插件名称,只用用于插件覆盖和细粒度控制加载哪些插件 install?: (lf: LogicFlow, logicFlow: LogicFlowConstructor) => void - render: ExtensionRender + render?: ExtensionRender destroy?: () => void } } diff --git a/packages/core/src/tool/TextEditTool.tsx b/packages/core/src/tool/TextEditTool.tsx index 1adce89d4..3ecc9bb44 100644 --- a/packages/core/src/tool/TextEditTool.tsx +++ b/packages/core/src/tool/TextEditTool.tsx @@ -1,5 +1,5 @@ import { createRef, Component } from 'preact/compat' -import { observer } from '..' +import { ElementState, observer } from '..' import LogicFlow from '../LogicFlow' import { GraphModel } from '../model' import { ElementType, EventType, ModelType } from '../constant' @@ -137,7 +137,7 @@ export class TextEditTool extends Component { } = this.props // 按下alt+enter表示输入完成 if (ev.key === 'Enter' && ev.altKey) { - textEditElement?.setElementState(0) + textEditElement?.setElementState(ElementState.DEFAULT) } } inputHandler = (ev) => { diff --git a/packages/extension/src/components/dnd-panel/index.ts b/packages/extension/src/components/dnd-panel/index.ts index 8742609c5..3a8d18d03 100644 --- a/packages/extension/src/components/dnd-panel/index.ts +++ b/packages/extension/src/components/dnd-panel/index.ts @@ -1,6 +1,6 @@ import LogicFlow from '@logicflow/core' -type ShapeItem = { +export type ShapeItem = { type?: string text?: string icon?: string @@ -9,6 +9,7 @@ type ShapeItem = { disabled?: boolean properties?: Record callback?: (lf: LogicFlow, container?: HTMLElement) => void + [key: string]: unknown } export class DndPanel { @@ -70,7 +71,7 @@ export class DndPanel { // if (typeof shapeItem.icon === 'string') { if (shapeItem.icon) { shape.style.backgroundImage = `url(${shapeItem.icon})` - shape.style.backgroundSize = 'contain' + // shape.style.backgroundSize = 'contain' // } else { // shape.appendChild(shapeItem.icon); }