因为现在做一个基于Activit的工作流OA,在设计过程中需要显示用户设计出来的流程图。

所以需要使用一个流程图插件,可以用来加载流程,也可以直接通过拖拽的方式设计流程。

思来想去,搜索了很多插件,最后选择了jsplubm这款插件

官网地址是jsplumbtoolkit.com

 

QQ截图20160706142516

 

 

流程包含了基本的用户任务,连接线。整个流程自上而下,且包含了“层”的概念,比如节点2和节点3是一个层的,节点4是单独一个层的,

主要是方便理清具体执行的顺序。

通过自己手动解析流程,可以展示基本的直线顺序流,并行切分汇聚顺序流,或者逆向的顺序流。当然这些都是后端的逻辑。

我是直接使用插件的flowchat demo (https://jsplumbtoolkit.com/community/demo/flowchart/index.html)直接改的

看了这个demo,我发现需要需要我手动在网页上添加用户任务

<div class="window jtk-node jsplumb-endpoint-anchor jsplumb-draggable jsplumb-connected" style="top: 150px; left: 120px; background-color: rgb(255, 255, 255);" id="sid-2-22737CD1-B482-2B90-5E6E-9E3BFB86FEF9">
节点2
<br> <br>
</div>

具体实施中,每个用户任务都用一个div表示 class是插件定义的 然后使用top和left属性确定他在页面上的位置。

id是用户任务的id

QQ截图20160706143702

当流程执行的时候,在某个时刻,永远只会执行某一层的一个或者多个用户任务。

所以我们必须有个节点的数据,这个数据是金字塔一样一层一层盖上去的。

第一层是起始节点,第二层是起始节点的下级节点,第三层是第二层所有节点的下级节点。。。。

然后在网页上,用DIV一个个画出来,并附上相关的属性。

//加载所有的节点
//data 所有的节点数据
//FlowID 流程定义ID
function loadMe(data,FlowID){
	nodes=new Array();
	 for(var i=0;i<data.length;i++){//遍历每一层 createActivity(cleanID(data[i]),i+1); }
               CreateSequence(FlowID,data);//创建连接线
               initcontrol(); // 初始化每个节点
         }
var nodes=new Array();
//构建一行节点
//itmes:这行的所有元素集合
//rows: 第几行 value >=1

function createActivity(items,rows){
	var height=50+(rows-1)*100 //高顿
	var MarginLeft=new Array();
	//更具不同的元素个数 初始化元素的左边距
	switch(items.length){
	case 1:
		MarginLeft[0]=180;
		break;
	case 2:
		MarginLeft[0]=120;
		MarginLeft[1]=240;
		break;
	case 3:
		MarginLeft[0]=60;
		MarginLeft[1]=180;
		MarginLeft[2]=300;
		break;
	case 4:
		MarginLeft[0]=10;
		MarginLeft[1]=130;
		MarginLeft[2]=250;
		MarginLeft[3]=380;
		break;
	}

    	for(var i=0;i<items.length;i++){
           var mdiv='<div class="window jtk-node" style="top:'+height+'px;left:'+MarginLeft[i]+'px" class=\"window jtk-node\" id=\"'+items[i].NODE_ID+'\">'+items[i].NODE_NAME +'<br /> <br /></div>';
           $('#canvas').append(mdiv);
       }
}

 

节点创建后就需要初始化节点的基本功能以及创建连接线了,基本代码如下

function CreateSequence(FlowID, Rowsdata) {

	var instance = window.jsp = jsPlumb.getInstance({
		// default drag options 默认拖动选项
		DragOptions : {
			cursor : 'pointer',
			zIndex : 2000
		},
		// the overlays to decorate each connection with. note that the label
		// overlay uses a function to generate the label text; in this
		// case it returns the 'labelText' member that we set on each connection
		// in the 'init' method below.
		// 默认连接线的样式
		ConnectionOverlays : [ [ "Arrow", { // 连接线箭头的样式
			location : 1,
			visible : true,
			id : "ARROW",
			length : 10,
			events : { // 点击连接线事件
				click : function() {
					alert("you clicked on the arrow overlay")
				}
			}
		} ],
		// [ "Label", {
		// location: 0.1,
		// id: "label",
		// cssClass: "aLabel",
		// events:{
		// tap:function() { alert("hey"); }
		// }
		// }]
		],
		Container : "canvas"
	});

	var basicType = {
		connector : "statemachine",

		proximityLimit : 1,
		paintStyle : {
			dashstyle : "0 0",
			strokeStyle : "#61B7CF",
			lineWidth : 2
		}, // dashstyle 虚设置为线
		hoverPaintStyle : {
			strokeStyle : "#61B7CF"
		},
	// overlays: [
	// "Arrow"
	// ]
	};
	instance.registerConnectionType("basic", basicType);

	// this is the paint style for the connecting lines..
	var connectorPaintStyle = {
		lineWidth : 2,
		strokeStyle : "#61B7CF",
		joinstyle : "round",
		outlineColor : "white",
		outlineWidth : 2
	},
	// .. and this is the hover style.
	connectorHoverStyle = {
		lineWidth : 2,
		strokeStyle : "#61B7CF",
		outlineWidth : 0,
		outlineColor : "#61B7CF"
	}, endpointHoverStyle = {
		fillStyle : "#61B7CF",
		strokeStyle : "#61B7CF"
	},
	// the definition of source endpoints (the small blue ones)
	sourceEndpoint = {
		endpoint : "Blank", // 隐藏连接点 显示连接点 Dot Blank
		paintStyle : {
			strokeStyle : "#7AB02C",
			fillStyle : "transparent",
			radius : 4,
			lineWidth : 3
		},
		maxConnections : -1,
		isSource : true,
		connectorOverlays : [ [ "Arrow", {
			width : 5,
			length : 1,
			location : 0
		} ] ],
		// gap 连接点的缺口 stub 线的最短高度和宽度 cornerRadius 连接点折点的弧度 StateMachine
		// Flowchart
		connector : [ "Flowchart", {
			stub : [ 20, 30 ],
			gap : 0,
			cornerRadius : 5,
			alwaysRespectStubs : true
		} ],
		connectorStyle : connectorPaintStyle,
		hoverPaintStyle : endpointHoverStyle,
		connectorHoverStyle : connectorHoverStyle,
		dragOptions : {},
		overlays : [ [ "Label", {
			location : [ 0.5, 1.5 ],
		// label: "Drag",
		// cssClass: "endpointSourceLabel",
		// visible:false
		} ] ]
	},
	// the definition of target endpoints (will appear when the user drags a
	// connection)
	targetEndpoint = {
		endpoint : "Blank", // DOt21
		paintStyle : {
			fillStyle : "#7AB02C",
			radius : 5
		},
		hoverPaintStyle : endpointHoverStyle,
		maxConnections : 30,
		dropOptions : {
			hoverClass : "hover",
			activeClass : "active"
		},
		isTarget : true,
		overlays : [ [ "Label", {
			location : [ 0.5, -0.5 ],
			label : "Drop",
			cssClass : "endpointTargetLabel",
			visible : false
		} ] ]
	}, init = function(connection) {
		// connection.getOverlay("label").setLabel(connection.sourceId.substring(15)
		// + "-" + connection.targetId.substring(15));
	};

	var _addEndpoints = function(toId, sourceAnchors, targetAnchors) {
		for (var i = 0; i < sourceAnchors.length; i++) {
			var sourceUUID = toId + sourceAnchors[i];
			instance.addEndpoint(toId, sourceEndpoint, {
				anchor : sourceAnchors[i],
				uuid : sourceUUID
			});
		}
		for (var j = 0; j < targetAnchors.length; j++) {
			var targetUUID = toId + targetAnchors[j];
			instance.addEndpoint(toId, targetEndpoint, {
				anchor : targetAnchors[j],
				uuid : targetUUID
			});
		}
	};

	// suspend drawing and initialise.
	instance.batch(function() {

				var Sequence;
				$.ajax({
					type : 'POST',
					async : false,
					url : "Form/GetSequenceByFlowID",
					data : "ActivityID=" + FlowID,
					success : function(data) {
						Sequence = data;
					},
					error : function(data) {
						alert("连接线数据加载失败:" + data)
					},
				// DataType:json
				});

				if (Sequence.length == 0) {// 只有一个开始节点

					$('.window.jtk-node').attr("class","window jtk-node jsplumb"+ "-endpoint-anchor jsplumb-draggable jsplumb-connected");
					return;
				}

				for (var x = 0; x < Sequence.length; x++) {
					_addEndpoints(Sequence[x].SOURE_NODE, [ "BottomCenter" ], [
							"TopCenter", "LeftMiddle", "RightMiddle" ]);
					_addEndpoints(Sequence[x].TARGET_NODE, [ "BottomCenter" ],
							[ "TopCenter", "LeftMiddle", "RightMiddle" ]);
					console.log('xxx');

				}

				instance.bind("connection", function(connInfo, originalEvent) {
					init(connInfo.connection);
				});

				// make all the window divs draggable
				instance.draggable(jsPlumb
						.getSelector(".flowchart-demo .window"), {
					grid : [ 20, 20 ]
				});


	// 判断连接线是不是撤回的
	function isBack(SOURE_NODE, TARGET_NODE) {

		for (var i = 0; i < Rowsdata.length; i++) {
			for (var x = 0; x < Rowsdata[i].length; x++) {
				if (Rowsdata[i][x].NODE_ID == SOURE_NODE) {
					SOURE_NODE = i;

				}
			}
		}
		for (var i = 0; i < Rowsdata.length; i++) {
			for (var x = 0; x < Rowsdata[i].length; x++) {
                            if (Rowsdata[i][x].NODE_ID == TARGET_NODE) { SOURE_NODE = i; }
                  }
               }
               return SOURE_NODE > SOURE_NODE;
	}

 

在这个方法中初始化每个节点,比如添加端点【endpoints 】,设置连接线的样式,设置箭头的样式,设置点击连接线的事件等等。

执行到这个的时候,流程图基本上就画出来了。

而且你可以拖动它。

Tips:

默认情况下端点是显示出来的,你还可以设置每个端点最多能连出或者连入多少条线,或者隐藏这个端点。

但隐藏后你就不能手动修改连接线了

附件

很久之前写的demo

http://pan.baidu.com/s/1miyEvCs

 

QQ截图20160706151946

 

参考文档:http://www.cnblogs.com/sggx/p/3836432.html

届ける言葉を今は育ててる
最后更新于 2017-10-13