首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Jointjs工作流程图实现

  • 25-04-18 22:41
  • 3581
  • 12767
juejin.cn

JointJS 是一个强大的 ​​JavaScript 图表库​​,专注于创建交互式的图表、流程图、拓扑图、UML 图等。它的核心优势在于​​灵活性​​和​​可扩展性,支持Vue和React集成,跨浏览器兼容。

基本的效果图

image.png

安装并使用

  • 官方文档:www.jointjs.com/docs

  • 这里是基于react的写法,初始化画布。

php
代码解读
复制代码
//初始化画布 import * as joint from '@joint/core'; export const initPaper: any = ( width: number = window.screen.width, height: number = window.screen.height, ) => { const graph = new joint.dia.Graph(); const paper = new joint.dia.Paper({ el: document.getElementById('paper'), model: graph, width: width, height: height, gridSize: 1, drawGrid: true, background: { color: '#fff', }, interactive: true, frozen: false, clickThreshold: 1, defaultLink: new joint.shapes.standard.Link({ router: { name: 'bezierrouter' }, attrs: { line: { stroke: 'gray', targetMarker: { d: 'M 8 -5 L 0 0 L 8 5 Z', }, }, }, }), linkView: joint.dia.LinkView.extend({ ...joint.dia.LinkView.prototype.options, doubleLinkTools: true, linkToolsOffset: 40, doubleLinkToolsOffset: 60, }), highlighting: { default: { name: 'stroke', options: { padding: 0, rx: 5, ry: 5, attrs: { 'stroke-width': 3, stroke: '#24b0e1', opacity: '.5', }, }, }, }, linkPinning: false, // 禁止自动创建悬空连线 }); return { paper, graph }; };
  • 创建节点并加入到画布中
php
代码解读
复制代码
//创建节点 const TaskNode = joint.dia.Element.define('task.Node', { attrs: { body: { refWidth: '100%', refHeight: '100%', fill: '#fff', stroke: '#000', strokeWidth: 1, rx: 5, ry: 5, cursor: 'pointer', }, label: { textVerticalAnchor: 'middle', textAnchor: 'middle', refX: '50%', refY: '50%', fontSize: 12, fill: '#333', }, // 状态图标组,包含图标和它的工具提示 statusIconGroup: { cursor: 'pointer', } }, ports: { groups: { right: { position: { name: 'right', args: { x: '90%', y: '50%' }, }, attrs: { circle: { magnet: true, stroke: 'gray', fill: '#fff', r: 6, }, }, markup: [ { tagName: 'circle', selector: 'circle', }, ], }, }, }, markup: [ { tagName: 'rect', selector: 'body', }, { tagName: 'text', selector: 'label', }, { tagName: 'g', selector: 'statusIconGroup', children: [ { tagName: 'text', selector: 'statusIcon', }, { tagName: 'title', selector: 'statusTooltip', } ] } ], }); export default TaskNode; //初始化画布时返回了画布的实例,所以这里把创建的节点加入到画布中 graph.addCell(newNode);
  • 自定义节点连线
ini
代码解读
复制代码
// 定义贝塞尔路由器 export const defineBezierRouter = () => { // @ts-ignore joint.routers.bezierrouter = (vertices: any[], args: any, linkView: any) => { // @ts-ignore vertices = joint.util.toArray(vertices).map(joint.g.Point); const sourcePoint: any = linkView.sourceBBox.center(); const targetPoint: any = linkView.targetBBox.center(); sourcePoint.y += 6; targetPoint.y -= 6; const controlPoint1 = new joint.g.Point(sourcePoint.x, sourcePoint.y + 80); const controlPoint2 = new joint.g.Point(targetPoint.x, targetPoint.y - 80); const points = new joint.g.Curve( sourcePoint, controlPoint1, controlPoint2, targetPoint, ).toPoints(); points.pop(); return vertices.concat(points); }; };
  • 在页面中使用,这里做参考,具体的事件处理逻辑根据需求参考官方文档
scss
代码解读
复制代码
useEffect(() => { // 4. 初始化画布 - 设置画布的基本属性和交互选项 const { paper, graph } = initPaper(); setPaper(paper); setGraph(graph); // 自定义的贝塞尔曲线 defineBezierRouter(); // 监听节点移动 paper.on('cell:pointermove', cellPointerMove); // 监听节点点击 paper.on('cell:pointerclick', CellPointerClick); // 监听节点双击 paper.on('cell:pointerdblclick', CellPointerClick); // 监听连接点击事件 paper.on('link:connect', handleLinkConnect); // 监听连接松开事件 paper.on('link:pointerup', handleLinkPointerUp); // 监听画布空白处的点击事件 paper.on('blank:pointerclick', handleBlankClick); // 监听画布空白处的点击事件 paper.on('blank:pointerdown', (evt: any, x: number, y: number) => { handleBlankPointerDown(evt, x, y, graph); }); // 添加右键菜单事件监听 paper.on('cell:contextmenu', handleBlankContextMenu); paper.on('element:magnet:contextmenu', portClick); return () => { // 移除事件 paper.off('element:magnet:contextmenu', portClick); paper.off('link:connect', handleLinkConnect); paper.off('link:pointerup', handleLinkPointerUp); paper.off('blank:pointerdown', handleBlankPointerDown); paper.off('blank:pointerclick', handleBlankClick); paper.off('cell:pointerclick', CellPointerClick); paper.off('cell:pointerdblclick', CellPointerClick); paper.off('cell:contextmenu', handleBlankContextMenu); paper.off('cell:pointermove', cellPointerMove); // 清除画布 graph.clear(); paper.remove(); };

结合业务做增删改查的思路

基本的效果图:

image.png

1.首先页面分为三个部分,左侧节点的拖拽基于react-dnd和react-dnd-html5-backend来实现的,中间是画布部分,右侧是表单,当选中节点时可以配置这个节点的参数。
2. 从左侧拖拽到画布中生成一个节点,当选中一个节点的时候,使用一个react状态来存储这个节点的信息,节点信息如下:

image.png

3. 每次创建一个节点到画布上时,会生成节点的一个唯一id,那么可以根据这个id去创建一个Map数据结构,形成一个key和value的映射。
arduino
代码解读
复制代码
//创建一个Map数据 const nodeMap = new Map(); //创建节点 const node = new TaskNode({ //这里是节点相关配置数据 position, size: { width, height }, attrs: attrs, }); // 将完整的节点数据存储在nodeMap中 nodeMap.set(node.id, { //节点相关数据 如右侧表单的数据 });
4.由于把节点的数据都存入了nodeMap中去了,如图:

image.png

5.每次需要去更新或者获取某个节点的数据时,就可以根据nodeMap去获取
csharp
代码解读
复制代码
// 获取当前节点在nodeMap中的数据 const currentNodeData = nodeMap.get(id) || {}; // 获设置当前节点在nodeMap中的数据 const currentNodeData = nodeMap.set(id) || {};
6. 为什么不使用对象去存储节点数据呢?,个人觉得因为object描述的是一个整体,这里节点的数据只是id对应value数据,而且在业务中我们会时长去做节点的数据更改,连线,新增节点,删除节点,配置节点数据等,Map更适合且性能更快点。
注:本文转载自juejin.cn的增删改查科学家的文章"https://juejin.cn/post/7493849132659556392"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

104
前端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top