实际工作中遇到一个问题,在html页面以树形节点的方式展示工作流程图。
echarts2的树形图可以实现,但是页面样式不够灵活。架构师从网上找来qunee插件,大致能满足客户要求。
qunee是"一套基于HTML5的网络图组件",详情可以去官网http://qunee.com查看。
这里只介绍如何用qunee来实现树形图。
在qunee的demo里找到
Treelayouter Demo (http://demo.qunee.com/#TreeLayouter Demo)
和Work Flow Demo中的
development guide (http://demo.qunee.com/#Development Guide)
本例需要将两者的效果结合。
流程图结构如下(局部放大):
流程图结构如下(完整):
节点数据是json格式,举例如下:
var test = { "children": [{ "children": [{ "children": null, "codeDescription": "2级节点", "nodeLevel": 2, "nodeName": "test1_1", "nodeOrder": 0 }], "codeDescription": "1级节点", "nodeLevel": 1, "nodeName": "test1", "nodeOrder": 0 }], "codeDescription": "根节点", "nodeLevel": 0, "nodeName": "test0", "nodeOrder": 0 }
完整的html代码,每一部分都有较详细的注释。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>Qunee Treelayout Demo 20160801 update</title> <!--引入qunee插件的js文件--> <script src="./qunee-min.js"></script> <!--引入json数据 --> <script src="./dataserver1.js"></script> </head> <body> <div id="root_box" style="width: 1000px; height: 600px; margin: auto; border: solid 1px #2898E0;"></div> <!-- <script type="text/javascript" src="work-process.js"></script> --> <script type="text/javascript"> //指定一个div元素,初始化qunee画布 var graph = new Q.Graph("root_box"); //graph.originAtCenter为false时表示设置左上角为坐标原点 graph.originAtCenter = false; //创建一个数组存放所有的子孙节点 var allChildren = []; //用来记录最大层级 var maxLevel = 1; //递归函数,将传入的数据创建成树形图的节点 function loadDatas(json, parent, layoutType) { json.forEach(function(data) { //获取最深的层级 if (data.nodeLevel > maxLevel) { maxLevel = data.nodeLevel; } var node = createNode(data.nodeName, parent, layoutType); allChildren.push(node); if (layoutType == Q.Consts.LAYOUT_TYPE_EVEN_VERTICAL) { node.vGap = 20; //设置孩子布局的垂直间距,hGap为水平间距 } //递归创建所有节点 if (data.children) { loadDatas(data.children, node, Q.Consts.LAYOUT_TYPE_EVEN_VERTICAL); } }); } //传入根节点(根节点属性中包含了所有子孙节点),生成树形图 function init(rootNode) { //建立一个数组用于存放主流程节点 var nodeL1Arr = []; //在本demo中,rootNode根节点不展示,根节点下的第一级节点作为主流程节点 if (rootNode.children) { rootNode.children.forEach(function(nodeL1) { var newNode = createStep(nodeL1.nodeName); nodeL1Arr.push(newNode); if (nodeL1.children) { loadDatas(nodeL1.children, newNode, Q.Consts.LAYOUT_TYPE_EVEN_VERTICAL); } }); } else { var newNode = createNode("没有流程信息"); } //设置树形图布局 setLayout(nodeL1Arr); } //创建单个流程节点 function createNode(name, from, layoutType) { var node = graph.createText(name); node.setStyle(Q.Styles.LABEL_BORDER, 1); node.setStyle(Q.Styles.LABEL_BORDER_STYLE, "#1D4876"); node.setStyle(Q.Styles.LABEL_FONT_SIZE, 16); node.setStyle(Q.Styles.LABEL_PADDING, 5); node.setStyle(Q.Styles.LABEL_SIZE, new Q.Size(70, 35)); node.setStyle(Q.Styles.LABEL_BACKGROUND_COLOR, "#FFF"); //节点是否可见 node.visible = true; //节点是否能用鼠标拖动,false为不能拖动 node.movable = false node.layoutType = layoutType; if (from) { node.parent = from; node.host = from; } if (from instanceof Q.Node) { //创建连线 var nodeEdge = graph.createEdge(from, node); if (from.layoutType == Q.Consts.LAYOUT_TYPE_EVEN_VERTICAL) { nodeEdge.edgeType = Q.Consts.EDGE_TYPE_VERTICAL_HORIZONTAL; } else { nodeEdge.edgeType = Q.Consts.EDGE_TYPE_ORTHOGONAL; } } return node; } //创建主流程节点 function createStep(label) { var node = graph.createText(label); node.setStyle(Q.Styles.LABEL_BORDER, 1); node.setStyle(Q.Styles.LABEL_BACKGROUND_COLOR, "#FFF"); node.setStyle(Q.Styles.LABEL_BORDER_STYLE, "#1D4876"); node.setStyle(Q.Styles.LABEL_FONT_SIZE, 20); node.setStyle(Q.Styles.LABEL_SIZE, new Q.Size(120, 50)); node.visible = true; //节点是否能用鼠标拖动,false为不能拖动 node.movable = false node.layoutType = Q.Consts.LAYOUT_TYPE_EVEN_VERTICAL; //node.vGap = 30;//设置孩子布局的垂直间距,hGap为水平间距 return node; } //创建连线 function createEdge(from, to, lineWidth, dash) { var edge = graph.createEdge(from, to); edge.setStyle(Q.Styles.EDGE_WIDTH, lineWidth || 3); edge.setStyle(Q.Styles.EDGE_COLOR, "#1D4876"); if (dash) { edge.setStyle(Q.Styles.EDGE_LINE_DASH, [ 10, 10 ]); } return edge; } //调整树状图各分支的位置,形成美观的对称结构 function moveNodes() { var rightBound = 0; //节点右边界 var rightX = 0 //用于记录最右侧节点的横坐标 var rightElementName; //边界节点的名称 var prevElement; //前一主流程 var dx = 20 * maxLevel; //移动基数20乘以获取的最大层级 graph.graphModel.forEachByTopoBreadthFirstSearch(function(element) { if (element instanceof Q.Node) { //每次移动,整个父子节点链的线条都会移动 graph.moveElements([ element ], dx, 0); if (!element.parent) { //如果节点横坐标小于上一节点的右边界,则移动节点,避免重合 if (element.x < rightBound) { graph.moveElements([ element ], rightBound - element.x, 0); } //如果主流程没有子流程,需要单独移动固定距离dx,否则连线会非常短 if (prevElement && !prevElement.hasChildren()) { graph.moveElements([ element ], dx, 0); } prevElement = element; } if (element.x >= rightX) { //更新最右侧节点横坐标的值 rightX = element.x; //rightX为最右侧节点的横坐标,加上该节点边框的宽度,得到最右侧边界的位置 rightBound = rightX + graph.getUIBounds(element).width; //获取最右侧节点的名称,用于打印测试 rightElementName = element.name; } } }); } graph.visibleFilter = function(node) { return node.visible !== false; } var nodeClicked; // 设置点击事件 graph.onclick = function(evt) { nodeClicked = evt.getData(); if (!nodeClicked) { Q.forEach(allChildren, function(p) { p.visible = true; p.invalidateVisibility(); }) graph.invalidate(); return; } //点击主流程节点,只显示子孙节点,隐藏其他节点 /* if (!nodeClicked.parent && !nodeClicked.from) { Q.log(nodeClicked); Q.forEach(allChildren, function(p) { var visible = p.isDescendantOf(nodeClicked); p.visible = visible; p.invalidateVisibility(); }) graph.invalidate(); } */ //点击主流程节点,显示或隐藏其子孙节点 if (!nodeClicked.parent && !nodeClicked.from&&nodeClicked.hasChildren()) { setAllChildren(nodeClicked); graph.invalidate(); } } //显示或隐藏子孙节点的函数 function setAllChildren(parent){ Q.forEach(parent.children, function(p) { p.visible = !p.visible; p.invalidateVisibility(); if(p.hasChildren()){ setAllChildren(p); } }) } //设置树形图布局 var layouter = new Q.TreeLayouter(graph); function setLayout(nodeL1Arr) { layouter.layoutType = Q.Consts.LAYOUT_TYPE_EVEN_HORIZONTAL; //qunee新特性,节点连线能够等长排列 layouter.parentChildrenDirection = Q.Consts.DIRECTION_BOTTOM_RIGHT; layouter.doLayout({ callback : function() { //graph.moveToCenter(1); graph.zoomToOverview(); moveNodes(); if (nodeL1Arr.length > 0) { var index = 0 nodeL1Arr.forEach(function(obj) { if (index > 0) { createEdge(nodeL1Arr[index - 1], obj); } index++; }); } } }); } init(test); </script> </body> </html>
附件有完整的代码和数据供测试用。
相关推荐
Flowable BPMN是一款开源的工作流引擎,它基于BPMN 2.0标准,提供了强大的业务流程管理和工作流实现能力。对于开发人员来说,能够在一个高效、直观的环境中设计和管理流程模型是至关重要的,而IntelliJ IDEA作为Java...
在“vue+element工作流程图”中,Element UI 可能被用来构建界面元素,如树形结构、表单等。 3. **流程图**:流程图是一种图形表示特定过程或系统的工具,通过图形方式清晰地展示各个步骤和决策点。在这个项目中,...
在IT领域,尤其是在Web...总的来说,这个“支持layui树编辑的插件”是一个强大且易用的工具,它为layui用户提供了树形结构编辑的功能,简化了开发流程,提高了开发效率,特别适合那些需要处理大量层次数据的Web应用。
WinForm流程图编辑器是基于C#编程语言和GDI+图形库开发的一款高效、实用的工具,主要用于创建和编辑各种流程图。GDI+(Graphics Device Interface Plus)是.NET Framework提供的一种强大的图形处理能力,使得开发者...
在给定的博客文章中,作者详细介绍了如何使用Raphael实现流程图的步骤。文章可能包含了以下内容: 1. **初始化Raphael画布**:在HTML中创建一个div元素,然后在JavaScript中使用`Raphael('div_id', width, height)`...
多系统兼容性、可移植性:由于只包括前台UI,因此二次开发者可很方便将本插件用在任何一种需要流程图的B/S系统应用上,流程图的详细实现逻辑完全交于后台程序开发者自己实现;对于后台,只要能返回/接收能被本插件...
在IT行业中,构建交互式流程图是常见的需求,特别是在项目管理、系统设计或者软件开发中。本主题将探讨如何利用PHP和JavaScript技术实现一个可拖动、可右击保存到数据库的流程图功能。虽然提供的压缩包没有包含...
在网页开发中,为了清晰地展示复杂的步骤流程,如用户注册、购物流程或者项目审批等,工作流程步骤进度插件显得尤为重要。ystep是一款基于jQuery的高效插件,它能帮助开发者轻松创建具有视觉吸引力的步骤进度条,...
本文将深入探讨myflow插件的特性、使用方法以及如何将其与后端程序集成,以实现流程图的可视化操作。 首先,myflow的核心功能在于其强大的绘图能力。通过简单的API调用,开发者可以轻松添加、删除、移动和连接流程...
antv流程图是一款基于antv x6框架的轻量级流程图绘制工具,适用于Web端进行灵活、可交互的流程图设计。antv是阿里巴巴开源的一系列数据可视化库,而x6则是antv中的一个核心组件,专注于提供强大的图形编辑和绘图能力...
在.NET Framework 2.0环境下,使用C#语言开发Windows Forms(Winform)应用程序,可以实现一个简单的流程图设计工具,其功能类似于知名的Visio软件。这个项目的主要目标是允许用户通过拖放操作来创建和编辑流程图。...
9. **运行图片**:可能包含的是应用运行时的截图,展示了功能的实现效果,帮助理解整个系统的外观和工作流程。 为了实现这个功能,开发者需要熟悉jQuery、Bootstrap的基本用法,理解如何通过JavaScript与后端接口...
- **业务流程管理**:在企业系统中,流程图可以清晰地展示工作流,帮助管理者理解和优化业务流程。 - **网络拓扑**:在IT领域,拓扑图用于可视化网络设备和连接,便于网络管理和故障排查。 - **软件设计**:在...
本资源提供的是一套基于C#和GDI+实现的WinForm流程图绘制代码,它允许用户在界面上动态拖动和即时刷新流程图元素,非常适合用于创建自定义的工作流或流程设计工具。 GDI+(Graphics Device Interface Plus)是.NET ...
在JavaScript(JS)中实现画工作流的流程图是一项技术挑战,它涉及到DOM操作、图形渲染和用户交互等多个方面。这个项目的核心目标是创建一个自定义的WEB工作流设计工具,让用户可以直观地构建和编辑流程图,而无需...
4. **渲染流程图**:最后,使用图形库(如Graphviz、JSPlumb等)重新渲染流程图,展示高亮效果。如果你的应用程序是Web应用,可以使用前端库(如d3.js或Fabric.js)来实现这个功能。 实现过程中可能遇到的问题及...
PAD图使用四个基本形状:决策节点、顺序节点、并行节点和操作节点,简化了复杂流程的可视化表达。 4. **判定表**:判定表是一种处理条件组合的工具,特别适合于处理复杂的逻辑判断。它列出了所有可能的输入条件及其...
在这个“d3js流程图代码”项目中,开发者使用D3.js实现了丰富的流程图功能,包括事件操作、缩放、平移、选中、保存和动态加载流程图数据等。接下来,我们将深入探讨这些功能的实现细节。 1. **基础架构** - **flow...
1、一个支持增加节点、删除节点、修改节点的流程图,增加节点可选择并行、串行、会签、下一节点并行等状态; 2、支持设置条件、删除条件、查看条件; 3、可直观显示已完成的节点和不可查看的节点,真正做到了流程...
这个组件为开发者提供了构建复杂流程图、工作流和图表的强大工具,旨在提高用户体验并简化开发流程。 在JavaScript的世界里,Butterfly扮演着重要的角色,因为它允许开发者在Web应用中创建动态和交互式的流程图。...