GooFlow.js 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087
  1. //定义一个区域图类:
  2. function GooFlow(bgDiv,property){
  3. if (navigator.userAgent.indexOf("MSIE 8.0")>0||navigator.userAgent.indexOf("MSIE 7.0")>0||navigator.userAgent.indexOf("MSIE 6.0")>0){GooFlow.prototype.useSVG="";
  4. }else{ GooFlow.prototype.useSVG="1";}
  5. //初始化区域图的对象
  6. this.$id=bgDiv.attr("id");
  7. this.$bgDiv=bgDiv;//最父框架的DIV
  8. this.$bgDiv.addClass("GooFlow");
  9. var width=(property.width||800)-2;
  10. var height=(property.height||500)-2;
  11. this.$bgDiv.css({width:width+"px",height:height+"px"});
  12. this.$tool=null;//左侧工具栏对象
  13. this.$head=null;//顶部标签及工具栏按钮
  14. this.$title=null;//流程图的名称
  15. this.$nodeRemark={};//每一种结点或按钮的说明文字,JSON格式,key为类名,value为用户自定义文字说明
  16. this.$nowType="cursor";//当前要绘制的对象类型
  17. this.$lineData={};
  18. this.$lineCount=0;
  19. this.$nodeData={};
  20. this.$nodeCount=0;
  21. this.$objectKey=null;
  22. this.$areaData={};
  23. this.$areaCount=0;
  24. this.$lineDom={};
  25. this.$nodeDom={};
  26. this.$areaDom={};
  27. this.$max=property.initNum||1;//计算默认ID值的起始SEQUENCE
  28. this.$focus="";//当前被选定的结点/转换线ID,如果没选中或者工作区被清空,则为""
  29. this.$cursor="default";//鼠标指针在工作区内的样式
  30. this.$editable=false;//工作区是否可编辑
  31. var headHeight=0;
  32. var tmp="";
  33. if(property.haveHead){
  34. tmp="<div class='GooFlow_head'><label title='"+(property.initLabelText||"newFlow_1")+"'>"+(property.initLabelText||"newFlow_1")+"</label><span></span>";
  35. for(var x=0;x<property.headBtns.length;++x){
  36. tmp+="<a href='javascript:void(0)' class='GooFlow_head_btn'><b class='ico_"+property.headBtns[x]+"'></b></a>"
  37. }
  38. tmp+="<span></span></div>";
  39. this.$head=$(tmp);
  40. this.$bgDiv.append(this.$head);
  41. headHeight=24;
  42. //以下是当工具栏按钮被点击时触发的事件自定义(虚函数),格式为function(),因为可直接用THIS操作对象本身,不用传参;用户可自行重定义:
  43. this.onBtnNewClick=null;//新建流程图按钮被点中
  44. this.onBtnOpenClick=null;//打开流程图按钮定义
  45. this.onBtnSaveClick=null;//保存流程图按钮定义
  46. this.onFreshClick=null;//重载流程图按钮定义
  47. if(property.headBtns)
  48. this.$head.on("click",{inthis:this},function(e){
  49. if(!e)e=window.event;
  50. var tar=e.target;
  51. if(tar.tagName=="DIV"||tar.tagName=="SPAN") return;
  52. else if(tar.tagName=="a") tar=tar.childNode[0];
  53. var This=e.data.inthis;
  54. //定义顶部操作栏按钮的事件
  55. switch($(tar).attr("class")){
  56. case "ico_new": if(This.onBtnNewClick!=null) This.onBtnNewClick();break;
  57. case "ico_open": if(This.onBtnOpenClick!=null) This.onBtnOpenClick();break;
  58. case "ico_save": if(This.onBtnSaveClick!=null) This.onBtnSaveClick();break;
  59. case "ico_undo": This.undo();break;
  60. case "ico_redo": This.redo();break;
  61. case "ico_reload" :if(This.onFreshClick!=null) This.onFreshClick();break;
  62. }
  63. });
  64. }
  65. var toolWidth=0;
  66. if(property.haveTool){
  67. // this.$bgDiv.append("<div class='GooFlow_tool'"+(property.haveHead? "":" style='margin-top:3px'")+"><div style='height:"+(height-headHeight-(property.haveHead? 7:10))+"px' class='GooFlow_tool_div'></div></div>");
  68. this.$bgDiv.append("<div class='GooFlow_tool'"+(property.haveHead? "":" style='margin-top:3px;width:150px;position: absolute;'")+"><div style='height:"+(height-headHeight-(property.haveHead? 7:10))+"px' class='GooFlow_tool_div'></div></div>");
  69. this.$tool=this.$bgDiv.find(".GooFlow_tool div");
  70. //未加代码:加入绘图工具按钮
  71. // this.$tool.append("<a href='javascript:void(0)' class='GooFlow_tool_btndown' id='"+this.$id+"_btn_cursor'><b class='ico_cursor'/></a><a href='javascript:void(0)' class='GooFlow_tool_btn' id='"+this.$id+"_btn_direct'><b class='ico_direct'/></a><a href='javascript:void(0)' class='GooFlow_tool_btn' id='"+this.$id+"_btn_start'><b class='ico_start'/></a><a href='javascript:void(0)' class='GooFlow_tool_btn' id='"+this.$id+"_btn_end'><b class='ico_end'/></a>");
  72. if(property.toolBtns&&property.toolBtns.length>0){
  73. tmp="<span/>";
  74. for(var i=0;i<property.toolBtns.length;++i){
  75. tmp+="<a href='javascript:void(0)' id='"+this.$id+"_btn_"+property.toolBtns[i]+"' class='GooFlow_tool_btn'><b class='ico_"+property.toolBtns[i]+"'/></a>";//加入自定义按钮
  76. }
  77. // this.$tool.append(tmp);
  78. }
  79. //加入分支和聚合结点,复合结点及区域划分框工具按钮
  80. //this.$tool.append("<span/>");
  81. toolWidth=60;
  82. this.$nowType="cursor";
  83. //绑定各个按钮的点击事件
  84. this.$tool.on("click",{inthis:this},function(e){
  85. return;
  86. if(!e)e=window.event;
  87. var tar;
  88. switch(e.target.tagName){
  89. case "SPAN":return false;
  90. case "DIV":return false;
  91. case "BUTTON":return false;
  92. case "B": tar=e.target.parentNode;break;
  93. case "A": tar=e.target;
  94. };
  95. var type=$(tar).attr("id").split("btn_")[1];
  96. e.data.inthis.switchToolBtn(type);
  97. return false;
  98. });
  99. this.$editable=true;//只有具有工具栏时可编辑
  100. }
  101. width=width-toolWidth-8;
  102. height=height-headHeight-(property.haveHead? 5:8);
  103. this.$bgDiv.append("<div class='GooFlow_work' style='width:"+(width)+"px;height:"+(height)+"px;"+(property.haveHead? "":"margin-top:3px;overflow:hidden")+"'></div>");
  104. this.$workArea=$("<div ondragover='window.event.preventDefault()' class='GooFlow_work_inner' style='width:"+width+"px;height:"+height+"px';></div>")
  105. .attr({"unselectable":"on","onselectstart":'return false',"onselect":'document.selection.empty()'});
  106. this.$bgDiv.children(".GooFlow_work").append(this.$workArea);
  107. this.$draw=null;//画矢量线条的容器
  108. this.initDraw("draw_"+this.$id,width,height);
  109. this.$group=null;
  110. this.initGroup(width,height);
  111. if(this.$editable){
  112. this.$workArea.on("click",{inthis:this},function(e){
  113. if(!e)e=window.event;
  114. if(!e.data.inthis.$editable)return;
  115. var type=e.data.inthis.$nowType;
  116. if(e.target.nodeName=="svg"){control.hidden()}
  117. if(type=="cursor"){
  118. var t=$(e.target);
  119. var n=t.prop("tagName");
  120. if(n=="svg"||(n=="DIV"&&t.prop("class").indexOf("GooFlow_work")>-1)||n=="LABEL"){
  121. e.data.inthis.blurItem();
  122. }
  123. return;
  124. }
  125. else if(type=="direct"||type=="group")return;
  126. var X,Y;
  127. var ev=mousePosition(e),t=getElCoordinate(this);
  128. X=ev.x-t.left+this.parentNode.scrollLeft;
  129. Y=ev.y-t.top+this.parentNode.scrollTop;
  130. var newname="node_"+e.data.inthis.$max;
  131. var datatype=e.data.inthis.$nowType;//start,end,node,task
  132. var realtype="";
  133. if(datatype=="start"){newname="开始";realtype="start"};
  134. if(datatype=="end" ){newname="结束";realtype="end"};
  135. if(datatype=="node" ){newname="跳转";realtype="decision"};
  136. if(datatype=="task"){newname="任务";realtype="task"};
  137. if(datatype=="fork"){newname="并行";realtype="fork"};
  138. if(datatype=="join"){newname="汇合";realtype="join"};
  139. if(datatype=="subprocess"){newname="子工作流";realtype="subprocess"};
  140. if(datatype=="transmit"){newname="转发";realtype="transmit"};
  141. var newjson={name:newname,left:X,top:Y,type:e.data.inthis.$nowType}
  142. newjson.realtype=realtype;
  143. newjson.name=newname;
  144. newjson.bpm_type="1"
  145. newjson.bpm_agree="同意"
  146. newjson.bpm_reject="退回"
  147. //task
  148. if(selectTask!=null&&datatype== "task"){
  149. for(var key in selectTask){
  150. newjson[key]=selectTask[key];
  151. }
  152. // console.log("task..............")
  153. //start
  154. }else if(selectStart!=null&&datatype=="start"){
  155. newjson.service_name=selectStart.service_name
  156. selectStart.count++
  157. //end
  158. }else if(selectEnd!=null&&datatype=="end"){
  159. for(var key in selectEnd){
  160. newjson[key]=selectEnd[key];
  161. }
  162. //decision
  163. }else if(selectDecision!=null&&datatype=="node"){
  164. for(var key in selectDecision){
  165. newjson[key]=selectDecision[key];
  166. }
  167. }else if(datatype=="fork"){
  168. }else if(datatype=="join"){
  169. }else if(datatype=="subprocess"){
  170. for(var key in selectSubprocess){
  171. newjson[key]=selectSubprocess[key];
  172. }
  173. }else if(datatype=="transmit"){
  174. for(var key in selectTransmit){
  175. newjson[key]=selectTransmit[key];
  176. }
  177. }
  178. // e.data.inthis.$max++;
  179. // e.data.inthis.addNode(e.data.inthis.$id+"_node_"+e.data.inthis.$max,newjson);
  180. e.data.inthis.addNode(composeId("node"),newjson);
  181. });
  182. //划线时用的绑定
  183. this.$workArea.mousemove({inthis:this},function(e){
  184. if(e.data.inthis.$nowType!="direct") return;
  185. var lineStart=$(this).data("lineStart");
  186. if(!lineStart)return;
  187. var ev=mousePosition(e),t=getElCoordinate(this);
  188. var X,Y;
  189. X=ev.x-t.left+this.parentNode.scrollLeft;
  190. Y=ev.y-t.top+this.parentNode.scrollTop;
  191. var line=document.getElementById("GooFlow_tmp_line");
  192. if(GooFlow.prototype.useSVG!=""){
  193. line.childNodes[0].setAttribute("d","M "+lineStart.x+" "+lineStart.y+" L "+X+" "+Y);
  194. line.childNodes[1].setAttribute("d","M "+lineStart.x+" "+lineStart.y+" L "+X+" "+Y);
  195. if(line.childNodes[1].getAttribute("marker-end")=="url(\"#arrow2\")")
  196. line.childNodes[1].setAttribute("marker-end","url(#arrow3)");
  197. else line.childNodes[1].setAttribute("marker-end","url(#arrow2)");
  198. }
  199. else line.points.value=lineStart.x+","+lineStart.y+" "+X+","+Y;
  200. });
  201. this.$workArea.mouseup({inthis:this},function(e){
  202. if(e.data.inthis.$nowType!="direct") return;
  203. $(this).css("cursor","auto").removeData("lineStart");
  204. var tmp=document.getElementById("GooFlow_tmp_line");
  205. if(tmp)e.data.inthis.$draw.removeChild(tmp);
  206. });
  207. //为了结点而增加的一些集体delegate绑定
  208. this.initWorkForNode();
  209. //对结点进行移动或者RESIZE时用来显示的遮罩层
  210. this.$ghost=$("<div class='rs_ghost'></div>").attr({"unselectable":"on","onselectstart":'return false',"onselect":'document.selection.empty()'});
  211. this.$bgDiv.append(this.$ghost);
  212. this.$textArea=$("<textarea></textarea>");
  213. this.$bgDiv.append(this.$textArea);
  214. this.$lineMove=$("<div class='GooFlow_line_move' style='display:none'></div>");//操作折线时的移动框
  215. this.$workArea.append(this.$lineMove);
  216. this.$lineMove.on("mousedown",{inthis:this},function(e){
  217. var lm=$(this);
  218. lm.css({"background-color":"#333"});
  219. var This=e.data.inthis;
  220. var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
  221. var X,Y;
  222. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
  223. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
  224. var p=This.$lineMove.position();
  225. var vX=X-p.left,vY=Y-p.top;
  226. var isMove=false;
  227. document.onmousemove=function(e){
  228. if(!e)e=window.event;
  229. var ev=mousePosition(e);
  230. var ps=This.$lineMove.position();
  231. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
  232. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
  233. if(This.$lineMove.data("type")=="lr"){
  234. X=X-vX;
  235. if(X<0) X=0;
  236. else if(X>This.$workArea.width())
  237. X=This.$workArea.width();
  238. This.$lineMove.css({left:X+"px"});
  239. }
  240. else if(This.$lineMove.data("type")=="tb"){
  241. Y=Y-vY;
  242. if(Y<0) Y=0;
  243. else if(Y>This.$workArea.height())
  244. Y=This.$workArea.height();
  245. This.$lineMove.css({top:Y+"px"});
  246. }
  247. isMove=true;
  248. }
  249. document.onmouseup=function(e){
  250. if(isMove){
  251. var p=This.$lineMove.position();
  252. if(This.$lineMove.data("type")=="lr")
  253. This.setLineM(This.$lineMove.data("tid"),p.left+3);
  254. else if(This.$lineMove.data("type")=="tb")
  255. This.setLineM(This.$lineMove.data("tid"),p.top+3);
  256. }
  257. This.$lineMove.css({"background-color":"transparent"});
  258. if(This.$focus==This.$lineMove.data("tid")){
  259. This.focusItem(This.$lineMove.data("tid"));
  260. }
  261. document.onmousemove=null;
  262. document.onmouseup=null;
  263. }
  264. });
  265. this.$lineOper=$("<div class='GooFlow_line_oper' style='display:none'><b class='b_l1'></b><b class='b_l2'></b><b class='b_l3'></b><b class='b_x'></b></div>");//选定线时显示的操作框
  266. this.$workArea.append(this.$lineOper);
  267. this.$lineOper.on("click",{inthis:this},function(e){
  268. if(!e)e=window.event;
  269. if(e.target.tagName!="B") return;
  270. var This=e.data.inthis;
  271. var id=$(this).data("tid");
  272. switch($(e.target).attr("class")){
  273. case "b_x":
  274. This.delLine(id);
  275. this.style.display="none";break;
  276. case "b_l1":
  277. This.setLineType(id,"lr");break;
  278. case "b_l2":
  279. This.setLineType(id,"tb");break;
  280. case "b_l3":
  281. This.setLineType(id,"sl");break;
  282. }
  283. });
  284. this.$workArea.append(this.$nodeOper);
  285. ;
  286. //下面绑定当结点/线/分组块的一些操作事件,这些事件可直接通过this访问对象本身
  287. //当操作某个单元(结点/线/分组块)被添加时,触发的方法,返回FALSE可阻止添加事件的发生
  288. //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值
  289. this.onItemAdd=null;
  290. //当操作某个单元(结点/线/分组块)被删除时,触发的方法,返回FALSE可阻止删除事件的发生
  291. //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值
  292. this.onItemDel=null;
  293. //当操作某个单元(结点/分组块)被移动时,触发的方法,返回FALSE可阻止移动事件的发生
  294. //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","area"两种取值,线line不支持移动
  295. this.onItemMove=null;
  296. //当操作某个单元(结点/线/分组块)被重命名时,触发的方法,返回FALSE可阻止重命名事件的发生
  297. //格式function(id,name,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值
  298. this.onItemRename=null;
  299. //当操作某个单元(结点/线)被由不选中变成选中时,触发的方法,返回FALSE可阻止选中事件的发生
  300. //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line"两种取值,"area"不支持被选中
  301. this.onItemFocus=null;
  302. //当操作某个单元(结点/线)被由选中变成不选中时,触发的方法,返回FALSE可阻止取消选中事件的发生
  303. //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line"两种取值,"area"不支持被取消选中
  304. this.onItemBlur=null;
  305. //当操作某个单元(结点/线/分组块)被重定义大小或造型时,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
  306. //格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值
  307. this.onItemResize=null;
  308. //当移动某条折线中段的位置,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
  309. //格式function(id,M):id是单元的唯一标识ID,M是中段的新X(或Y)的坐标
  310. this.onLineMove=null;
  311. //当变换某条连接线的类型,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
  312. //格式function(id,type):id是单元的唯一标识ID,type是连接线的类型,"sl":直线,"lr":中段可左右移动的折线,"tb":中段可上下移动的折线
  313. this.onLineSetType=null;
  314. //当用重色标注某个结点/转换线时触发的方法,返回FALSE可阻止重定大小/造型事件的发生
  315. //格式function(id,type,mark):id是单元的唯一标识ID,type是单元类型("node"结点,"line"转换线),mark为布尔值,表示是要标注TRUE还是取消标注FALSE
  316. this.onItemMark=null;
  317. if(property.useOperStack){//如果要使用堆栈记录操作并提供“撤销/重做”的功能
  318. this.$undoStack=[];
  319. this.$redoStack=[];
  320. this.$isUndo=0;
  321. ///////////////以下是构造撤销操作/重做操作的方法
  322. //为了节省浏览器内存空间,undo/redo中的操作缓存栈,最多只可放40步操作;超过40步时,将自动删掉最旧的一个缓存
  323. this.pushOper=function(funcName,paras){
  324. var len=this.$undoStack.length;
  325. if(this.$isUndo==1){
  326. this.$redoStack.push([funcName,paras]);
  327. this.$isUndo=false;
  328. if(this.$redoStack.length>40) this.$redoStack.shift();
  329. }else{
  330. this.$undoStack.push([funcName,paras]);
  331. if(this.$undoStack.length>40) this.$undoStack.shift();
  332. if(this.$isUndo==0){
  333. this.$redoStack.splice(0,this.$redoStack.length);
  334. }
  335. this.$isUndo=0;
  336. }
  337. };
  338. //将外部的方法加入到GooFlow对象的事务操作堆栈中,在过后的undo/redo操作中可以进行控制,一般用于对流程图以外的附加信息进行编辑的事务撤销/重做控制;
  339. //传参func为要执行方法对象,jsonPara为外部方法仅有的一个面向字面的JSON传参,由JSON对象带入所有要传的信息;
  340. //提示:为了让外部方法能够被UNDO/REDO,需要在编写这些外部方法实现时,加入对该方法执行后效果回退的另一个执行方法的pushExternalOper
  341. this.pushExternalOper=function(func,jsonPara){
  342. this.pushOper("externalFunc",[func,jsonPara]);
  343. };
  344. //撤销上一步操作
  345. this.undo=function(){
  346. if(this.$undoStack.length==0) return;
  347. var tmp=this.$undoStack.pop();
  348. this.$isUndo=1;
  349. if(tmp[0]=="externalFunc"){
  350. tmp[1][0](tmp[1][1]);
  351. }
  352. else{
  353. //传参的数量,最多支持5个.
  354. switch(tmp[1].length){
  355. case 0:this[tmp[0]]();break;
  356. case 1:this[tmp[0]](tmp[1][0]);break;
  357. case 2:this[tmp[0]](tmp[1][0],tmp[1][1]);break;
  358. case 3:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2]);break;
  359. case 4:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3]);break;
  360. case 5:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4]);break;
  361. }
  362. }
  363. };
  364. //重做最近一次被撤销的操作
  365. this.redo=function(){
  366. if(this.$redoStack.length==0) return;
  367. var tmp=this.$redoStack.pop();
  368. this.$isUndo=2;
  369. if(tmp[0]=="externalFunc"){
  370. tmp[1][0](tmp[1][1]);
  371. }
  372. else{
  373. //传参的数量,最多支持5个.
  374. switch(tmp[1].length){
  375. case 0:this[tmp[0]]();break;
  376. case 1:this[tmp[0]](tmp[1][0]);break;
  377. case 2:this[tmp[0]](tmp[1][0],tmp[1][1]);break;
  378. case 3:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2]);break;
  379. case 4:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3]);break;
  380. case 5:this[tmp[0]](tmp[1][0],tmp[1][1],tmp[1][2],tmp[1][3],tmp[1][4]);break;
  381. }
  382. }
  383. };
  384. }
  385. }
  386. }
  387. GooFlow.prototype={
  388. useSVG:"",
  389. getSvgMarker:function(id,color){
  390. // var m=document.createElement("marker");
  391. var m=document.createElementNS("http://www.w3.org/2000/svg","marker");
  392. m.setAttribute("id",id);
  393. m.setAttribute("viewBox","0 0 24 24");
  394. m.setAttribute("refX",8);
  395. m.setAttribute("refY",15);
  396. m.setAttribute("markerUnits","strokeWidth");
  397. m.setAttribute("markerWidth",11);
  398. m.setAttribute("markerHeight",11);
  399. m.setAttribute("orient","auto");
  400. var path=document.createElementNS("http://www.w3.org/2000/svg","path");
  401. path.setAttribute("d","M9.297 15c0 0.125-0.063 0.266-0.156 0.359l-7.281 7.281c-0.094 0.094-0.234 0.156-0.359 0.156s-0.266-0.063-0.359-0.156l-0.781-0.781c-0.094-0.094-0.156-0.219-0.156-0.359 0-0.125 0.063-0.266 0.156-0.359l6.141-6.141-6.141-6.141c-0.094-0.094-0.156-0.234-0.156-0.359s0.063-0.266 0.156-0.359l0.781-0.781c0.094-0.094 0.234-0.156 0.359-0.156s0.266 0.063 0.359 0.156l7.281 7.281c0.094 0.094 0.156 0.234 0.156 0.359z");
  402. path.setAttribute("fill",color);
  403. path.setAttribute("stroke-width",0);
  404. m.appendChild(path);
  405. return m;
  406. },
  407. initDraw:function(id,width,height){
  408. var elem;
  409. if(GooFlow.prototype.useSVG!=""){
  410. // alert("can use svg")
  411. // this.$draw=document.createElement("svg");
  412. this.$draw=document.createElementNS("http://www.w3.org/2000/svg","svg");//可创建带有指定命名空间的元素节点
  413. this.$workArea.prepend(this.$draw);
  414. var defs=document.createElementNS("http://www.w3.org/2000/svg","defs");
  415. this.$draw.appendChild(defs);
  416. defs.appendChild(GooFlow.prototype.getSvgMarker("arrow1","#333")); /*箭头颜色*/
  417. defs.appendChild(GooFlow.prototype.getSvgMarker("arrow2","#ff3300"));
  418. defs.appendChild(GooFlow.prototype.getSvgMarker("arrow3","#ff3300"));
  419. }
  420. else{
  421. // alert("cannot use svg")
  422. this.$draw = document.createElement("v:group");
  423. this.$draw.coordsize = width+","+height;
  424. this.$workArea.prepend("<div class='GooFlow_work_vml' style='position:relative;width:"+width*2+"px;height:"+height*2+"px'></div>");
  425. this.$workArea.children("div")[0].insertBefore(this.$draw,null);
  426. }
  427. this.$draw.id = id;
  428. this.$draw.style.width = width + "px";
  429. this.$draw.style.height = +height + "px";
  430. //绑定连线的点击选中以及双击编辑事件
  431. var tmpClk=null;
  432. if(GooFlow.prototype.useSVG!="") tmpClk="g";
  433. else tmpClk="PolyLine";
  434. $(this.$draw).delegate(tmpClk,"click",{inthis:this},function(e){
  435. e.data.inthis.focusItem(this.id,true);
  436. });
  437. if(this.$editable)
  438. $(this.$draw).delegate(tmpClk,"dblclick",{inthis:this},function(e){
  439. var oldTxt,x,y,from,to;
  440. var This=e.data.inthis;
  441. if(GooFlow.prototype.useSVG!=""){
  442. oldTxt=this.childNodes[2].textContent;
  443. from=this.getAttribute("from").split(",");
  444. to=this.getAttribute("to").split(",");
  445. }else{
  446. oldTxt=this.childNodes[1].innerHTML;
  447. var n=this.getAttribute("fromTo").split(",");
  448. from=[n[0],n[1]];
  449. to=[n[2],n[3]];
  450. }
  451. if(This.$lineData[this.id].type=="lr"){
  452. from[0]=This.$lineData[this.id].M;
  453. to[0]=from[0];
  454. }
  455. else if(This.$lineData[this.id].type=="tb"){
  456. from[1]=This.$lineData[this.id].M;
  457. to[1]=from[1];
  458. }
  459. x=(parseInt(from[0],10)+parseInt(to[0],10))/2-60;
  460. y=(parseInt(from[1],10)+parseInt(to[1],10))/2-12;
  461. var t=getElCoordinate(This.$workArea[0]);
  462. This.$textArea.val(oldTxt).css({display:"block",width:120,height:14,
  463. left:t.left+x-This.$workArea[0].parentNode.scrollLeft,
  464. top:t.top+y-This.$workArea[0].parentNode.scrollTop}).data("id",This.$focus).focus();
  465. This.$workArea.parent().one("mousedown",function(e){
  466. This.setName(This.$textArea.data("id"),This.$textArea.val(),"line");
  467. This.$textArea.val("").removeData("id").hide();
  468. });
  469. });
  470. },
  471. initGroup:function(width,height){
  472. this.$group=$("<div class='GooFlow_work_group' style='width:"+width+"px;height:"+height+"px'></div>");//存放背景区域的容器
  473. this.$workArea.prepend(this.$group);
  474. if(!this.$editable) return;
  475. //区域划分框操作区的事件绑定
  476. this.$group.on("mousedown",{inthis:this},function(e){//绑定RESIZE功能以及移动功能
  477. var This=e.data.inthis;
  478. if(This.$nowType!="group") return;
  479. if(This.$textArea.css("display")=="block"){
  480. This.setName(This.$textArea.data("id"),This.$textArea.val(),"area");
  481. This.$textArea.val("").removeData("id").hide();
  482. return false;
  483. };
  484. if(!e)e=window.event;
  485. var cursor=$(e.target).css("cursor");
  486. var id=e.target.parentNode;
  487. switch(cursor){
  488. case "nw-resize":id=id.parentNode;break;
  489. case "w-resize":id=id.parentNode;break;
  490. case "n-resize":id=id.parentNode;break;
  491. case "move":break;
  492. default:return;
  493. }
  494. id=id.id;
  495. var hack=1;
  496. if(navigator.userAgent.indexOf("8.0")!=-1) hack=0;
  497. var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
  498. This.$ghost.css({display:"block",
  499. width:This.$areaData[id].width-2+"px", height:This.$areaData[id].height-2+"px",
  500. top:This.$areaData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
  501. left:This.$areaData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:cursor});
  502. var X,Y;
  503. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
  504. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
  505. if(cursor!="move"){
  506. var vX=(This.$areaData[id].left+This.$areaData[id].width)-X;
  507. var vY=(This.$areaData[id].top+This.$areaData[id].height)-Y;
  508. }
  509. else{
  510. var vX=X-This.$areaData[id].left;
  511. var vY=Y-This.$areaData[id].top;
  512. }
  513. var isMove=false;
  514. This.$ghost.css("cursor",cursor);
  515. document.onmousemove=function(e){
  516. if(!e)e=window.event;
  517. var ev=mousePosition(e);
  518. if(cursor!="move"){
  519. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft-This.$areaData[id].left+vX;
  520. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop-This.$areaData[id].top+vY;
  521. if(X<200) X=200;
  522. if(Y<100) Y=100;
  523. switch(cursor){
  524. case "nw-resize":This.$ghost.css({width:X-2+"px",height:Y-2+"px"});break;
  525. case "w-resize":This.$ghost.css({width:X-2+"px"});break;
  526. case "n-resize":This.$ghost.css({height:Y-2+"px"});break;
  527. }
  528. }
  529. else{
  530. X=ev.x-vX;Y=ev.y-vY;
  531. if(X<t.left-This.$workArea[0].parentNode.scrollLeft)
  532. X=t.left-This.$workArea[0].parentNode.scrollLeft;
  533. else if(X+This.$workArea[0].parentNode.scrollLeft+This.$areaData[id].width>t.left+This.$workArea.width())
  534. X=t.left+This.$workArea.width()-This.$workArea[0].parentNode.scrollLeft-This.$areaData[id].width;
  535. if(Y<t.top-This.$workArea[0].parentNode.scrollTop)
  536. Y=t.top-This.$workArea[0].parentNode.scrollTop;
  537. else if(Y+This.$workArea[0].parentNode.scrollTop+This.$areaData[id].height>t.top+This.$workArea.height())
  538. Y=t.top+This.$workArea.height()-This.$workArea[0].parentNode.scrollTop-This.$areaData[id].height;
  539. This.$ghost.css({left:X+hack+"px",top:Y+hack+"px"});
  540. }
  541. isMove=true;
  542. }
  543. document.onmouseup=function(e){
  544. This.$ghost.empty().hide();
  545. document.onmousemove=null;
  546. document.onmouseup=null;
  547. if(!isMove)return;
  548. if(cursor!="move")
  549. This.resizeArea(id,This.$ghost.outerWidth(),This.$ghost.outerHeight());
  550. else
  551. This.moveArea(id,X+This.$workArea[0].parentNode.scrollLeft-t.left,Y+This.$workArea[0].parentNode.scrollTop-t.top);
  552. }
  553. });
  554. //绑定修改文字说明功能
  555. this.$group.on("dblclick",{inthis:this},function(e){
  556. var This=e.data.inthis;
  557. if(This.$nowType!="group") return;
  558. if(!e)e=window.event;
  559. if(e.target.tagName!="LABEL") return false;
  560. var oldTxt=e.target.innerHTML;
  561. var p=e.target.parentNode;
  562. var x=parseInt(p.style.left,10)+18,y=parseInt(p.style.top,10)+1;
  563. var t=getElCoordinate(This.$workArea[0]);
  564. This.$textArea.val(oldTxt).css({display:"block",width:100,height:14,
  565. left:t.left+x-This.$workArea[0].parentNode.scrollLeft,
  566. top:t.top+y-This.$workArea[0].parentNode.scrollTop}).data("id",p.id).focus();
  567. This.$workArea.parent().one("mousedown",function(e){
  568. if(This.$textArea.css("display")=="block"){
  569. This.setName(This.$textArea.data("id"),This.$textArea.val(),"area");
  570. This.$textArea.val("").removeData("id").hide();
  571. }
  572. });
  573. return false;
  574. });
  575. this.$group.on("click",{inthis:this},function(e){
  576. var This=e.data.inthis;
  577. if(This.$nowType!="group") return;
  578. if(!e)e=window.event;
  579. switch($(e.target).attr("class")){
  580. case "rs_close": This.delArea(e.target.parentNode.parentNode.id);return false;//删除该分组区域
  581. case "bg": return false;
  582. }
  583. switch(e.target.tagName){
  584. case "LABEL": return false;
  585. case "B"://绑定变色功能
  586. var id=e.target.parentNode.id;
  587. switch(This.$areaData[id].color){
  588. case "red": This.setAreaColor(id,"yellow");break;
  589. case "yellow": This.setAreaColor(id,"blue");break;
  590. case "blue": This.setAreaColor(id,"green");break;
  591. case "green": This.setAreaColor(id,"red");break;
  592. }
  593. return false;
  594. }
  595. var X,Y;
  596. var ev=mousePosition(e),t=getElCoordinate(this);
  597. X=ev.x-t.left+this.parentNode.parentNode.scrollLeft;
  598. Y=ev.y-t.top+this.parentNode.parentNode.scrollTop;
  599. var color=["red","yellow","blue","green"];
  600. e.data.inthis.addArea(e.data.inthis.$id+"_area_"+e.data.inthis.$max,{name:"area_"+e.data.inthis.$max,left:X,top:Y,color:color[e.data.inthis.$max%4],width:200,height:100});
  601. e.data.inthis.$max++;
  602. return false;
  603. });
  604. },
  605. //每一种类型结点及其按钮的说明文字
  606. setNodeRemarks:function(remark){
  607. if(property.haveTool==false){return;}
  608. this.$tool.children("a").each(function(){
  609. this.title=remark[$(this).attr("id").split("btn_")[1]];
  610. });
  611. this.$nodeRemark=remark;
  612. },
  613. //切换左边工具栏按钮,传参TYPE表示切换成哪种类型的按钮
  614. switchToolBtn:function(type){
  615. if(!this.$tool)return
  616. this.$tool.children("#"+this.$id+"_btn_"+this.$nowType).attr("class","GooFlow_tool_btn");
  617. if(this.$nowType=="group"){
  618. this.$workArea.prepend(this.$group);
  619. for(var key in this.$areaDom) this.$areaDom[key].addClass("lock").children("div:eq(1)").css("display","none");
  620. }
  621. this.$nowType=type;
  622. this.$tool.children("#"+this.$id+"_btn_"+type).attr("class","GooFlow_tool_btndown");
  623. if(this.$nowType=="group"){
  624. this.blurItem();
  625. this.$workArea.append(this.$group);
  626. for(var key in this.$areaDom) this.$areaDom[key].removeClass("lock").children("div:eq(1)").css("display","");
  627. }
  628. if(this.$textArea.css("display")=="none") this.$textArea.removeData("id").val("").hide();
  629. },
  630. //增加一个流程结点,传参为一个JSON,有id,name,top,left,width,height,type(结点类型)等属性
  631. addNode:function(id,json){
  632. if(this.onItemAdd!=null&&!this.onItemAdd(id,"node")){
  633. return;
  634. };
  635. if(this.$undoStack){
  636. this.pushOper("delNode",[id]);
  637. }
  638. var mark=json.mark? " item_mark":"";
  639. for(var key in this.$nodeData){
  640. if(this.$nodeData[key].id==id){
  641. console.log("same id")
  642. return;
  643. }
  644. }
  645. //计算$max最大值,防止ID重复
  646. // var IDMAX=parseInt(id.replace(/[^0-9]/ig,""));
  647. // if(this.$max<=IDMAX){
  648. // this.$max=IDMAX+1
  649. // };
  650. json.id=id;
  651. if(!json.step){json.step=0}
  652. if(json.type!="start"&&json.type!="end"){
  653. if(json)
  654. json.width=json.width? json.width:40;
  655. /* 再改,"并行"、"可变" 节点的高度改为 28px 了。Lin
  656. * 同时,并行/分支 节点的属性窗口,不能改名称 -- 只显示
  657. json.height=json.height? json.height:40;
  658. */
  659. if (json.name == "并行") // 实际上,只有 "并行","可变" 是在 "并行" 属性窗口里,设置后才成为 "可变"。Lin
  660. json.height=json.height? json.height:30;
  661. else
  662. json.height=json.height? json.height:40;
  663. if(json.top<0)json.top=0;
  664. if(json.left<0)json.left=0;
  665. var hack=0;
  666. if(navigator.userAgent.indexOf("8.0")!=-1) hack=2;
  667. //this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>");
  668. //decision图标
  669. if(json.type=="node"){
  670. // console.log("add 1 node")
  671. /* 再改,去掉 <table 的宽、高指定,由里面的内容决定 -- 可以由 .GooFlow .ico_node2 来指定。Lin
  672. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+" node_decision' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style=';position:absolute'>"+json.name+"</div></div>"); */
  673. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+" node_decision' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style=';position:absolute'>"+json.name+"</div></div>");
  674. // this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='transform:rotate(45deg);top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div><div class='span' style='transform:rotate(-45deg);position:absolute'>"+json.name+"</div></div>");
  675. }
  676. //task图标
  677. if(json.type=="task"){
  678. if(json.name.length*12>json.width){json.width=json.name.length*13}
  679. // console.log("add 1 task")
  680. //this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>");
  681. if(json.height<40){json.height=40}
  682. if(json.width<80){json.width=80}
  683. /* "N" 改为 "No"。Lin
  684. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px;border-radius:5px;background:initial'><table cellspacing='1' style='width:"+(json.width-4)+"px;height:"+(json.height-4)+"px;' ><tr><td class='ico'></td></tr></table><div style='display:none;height:0px'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_rejectline'>N</div><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute;left:"+10+"px;top:"+15+"px;'>"+json.name+"</div></div>"); */
  685. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px;border-radius:5px;background:initial'><table cellspacing='1' style='width:"+(json.width-4)+"px;height:"+(json.height-4)+"px;' ><tr><td class='ico'></td></tr></table><div style='display:none;height:0px'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_rejectline'>No</div><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute;left:"+10+"px;top:"+15+"px;'>"+json.name+"</div></div>");
  686. }
  687. //transmit转发图标
  688. if(json.type=="transmit"){
  689. if(json.name.length*12>json.width){json.width=json.name.length*13}
  690. // console.log("add 1 task")
  691. //this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>");
  692. if(json.height<40){json.height=40}
  693. if(json.width<80){json.width=80}
  694. /* 再改,去掉 <table 的宽、高指定,由里面的内容决定 -- 可以由 <table 里的内容来指定。Lin
  695. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px;border-radius:20px;background:initial ;background-color:transparent'><table cellspacing='1' style='width:"+(json.width-4)+"px;height:"+(json.height-4)+"px;' ><tr><td class='ico'></td></tr></table><div style='display:none;height:0px'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute;left:"+10+"px;top:"+15+"px;'>"+json.name+"</div></div>"); */
  696. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px;border-radius:20px;background:initial ;background-color:transparent'><table cellspacing='1'><tr><td class='ico'></td></tr></table><div style='display:none;height:0px'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute;left:"+10+"px;top:"+15+"px;'>"+json.name+"</div></div>");
  697. }
  698. //子流程
  699. if(json.type=="subprocess"){
  700. if(json.name.length*12>json.width){json.width=json.name.length*13}
  701. // console.log("add 1 task")
  702. //this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>");
  703. if(json.height<40){json.height=40}
  704. if(json.width<80){json.width=80}
  705. /* "N" 改为 "No"。Lin
  706. * 再改,去掉 <table 的宽、高指定,由里面的内容决定 -- 可以由 <table 里的内容来指定。Lin
  707. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='border:#333 2px dashed;top:"+json.top+"px;left:"+json.left+"px;border-radius:20px;background:initial ;background-color:transparent'><table cellspacing='1' style='width:"+(json.width-4)+"px;height:"+(json.height-4)+"px;' ><tr><td class='ico'></td></tr></table><div style='display:none;height:0px'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_rejectline'>N</div><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute;left:"+10+"px;top:"+15+"px;'>"+json.name+"</div></div>"); */
  708. /* 再改,不能去掉 <table 的宽、高指定 -- 像 "task" 一样
  709. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='border:#333 2px dashed;top:"+json.top+"px;left:"+json.left+"px;border-radius:20px;background:initial ;background-color:transparent'><table cellspacing='1'><tr><td class='ico'></td></tr></table><div style='display:none;height:0px'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_rejectline'>No</div><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute;left:"+10+"px;top:"+15+"px;'>"+json.name+"</div></div>");*/
  710. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+"' id='"+id+"' style='border:#333 2px dashed;top:"+json.top+"px;left:"+json.left+"px;border-radius:20px;background:initial ;background-color:transparent'><table cellspacing='1' style='width:"+(json.width-4)+"px;height:"+(json.height-4)+"px;'><tr><td class='ico'></td></tr></table><div style='display:none;height:0px'><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_rejectline'>No</div><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute;left:"+10+"px;top:"+15+"px;'>"+json.name+"</div></div>");
  711. }
  712. //fork
  713. if(json.type=="fork"){
  714. // console.log("add 1 fork")
  715. /* 再改,去掉 <table 的宽、高指定,由里面的内容决定 -- 可以由 .GooFlow .ico_fork2 来指定。Lin
  716. * 在上面的 if(json) 那,用的是默认值 40 -- 调用本方法(addNode)时,json.width 和 json.height 都没有赋值
  717. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+" node_fork' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>"); */
  718. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+" node_fork' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>");
  719. }
  720. //join
  721. if(json.type=="join"){
  722. // console.log("add 1 join")
  723. /* 再改,去掉 <table 的宽、高指定,由里面的内容决定 -- 可以由 .GooFlow .ico_join2 来指定。Lin
  724. * 在上面的 if(json) 那,用的是默认值 40 -- 调用本方法(addNode)时,json.width 和 json.height 都没有赋值
  725. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+" node_join' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>"); */
  726. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+" node_join' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>");
  727. }
  728. //join
  729. if(json.type=="foreach"){
  730. // console.log("add 1 foreach")
  731. /* 再改,去掉 <table 的宽、高指定,由里面的内容决定 -- 可以由 .GooFlow .ico_foreach2 来指定。Lin
  732. * 在上面的 if(json) 那,用的是默认值 40 -- 调用本方法(addNode)时,json.width 和 json.height 都没有赋值
  733. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+" node_foreach' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px;'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>");*/
  734. this.$nodeDom[id]=$("<div class='GooFlow_item"+mark+" node_foreach' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='1'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_close'></div><div class='rs_control'></div></div></div><div class='span' style='position:absolute'>"+json.name+"</div></div>");
  735. }
  736. if(json.type=='complex') this.$nodeDom[id].addClass('item_complex');
  737. }
  738. else{
  739. json.width=21;json.height=21;
  740. // console.log("add start end")
  741. this.$nodeDom[id]=$("<div class='GooFlow_item item_round"+mark+"' id='"+id+"' style='top:"+json.top+"px;left:"+json.left+"px'><table cellspacing='0'><tr><td class='ico'><b class='ico_"+json.type+"2"+"'></b></td></tr></table><div style='display:none'><div class='rs_opener'><div class='rs_control'></div></div></div><div class='span'>"+json.name+"</div></div>");
  742. }
  743. var ua=navigator.userAgent.toLowerCase();
  744. if(ua.indexOf('msie')!=-1 && ua.indexOf('8.0')!=-1)
  745. this.$nodeDom[id].css("filter","progid:DXImageTransform.Microsoft.Shadow(color=#94AAC2,direction=135,strength=2)");
  746. this.$workArea.append(this.$nodeDom[id]);
  747. this.$nodeData[id]=json;
  748. ++this.$nodeCount;
  749. },
  750. initWorkForNode:function(){
  751. this.$workArea.delegate(".GooFlow_item","click",{inthis:this},function(e){
  752. e.data.inthis.focusItem(this.id,true);
  753. $(this).removeClass("item_mark");
  754. });
  755. //自定义 绑定双击事件
  756. // this.$workArea.delegate(".GooFlow_item > .settask","dblclick",{inthis:this},function(e){
  757. // control_planel(this.parentNode.id);
  758. // });
  759. var bbb=1
  760. var time=0
  761. setInterval(function(){
  762. time=time+100;
  763. if(time>=1000){
  764. time=0;}
  765. },100)
  766. var temptarget=null
  767. //双击检测
  768. var doubleClick= function(){
  769. return function(){
  770. var e=window.event;
  771. var temp=$(e.target).parents("div")[0].id
  772. if(e.target.className=="span")return
  773. if(bbb==2){
  774. temptarget=temp
  775. }
  776. temptarget
  777. if(bbb==4&&time<=1500&&temptarget==temp){
  778. //弹窗编辑
  779. settingIt(this)
  780. }
  781. if(bbb==4){
  782. bbb=1;temptarget=null
  783. }else{bbb=bbb+1}
  784. }
  785. }
  786. $(".GooFlow_item").on("mousedown",doubleClick()).on("mouseup",doubleClick())
  787. //绑定用鼠标移动事件
  788. this.$workArea.delegate(".ico","mousedown",{inthis:this},function(e){
  789. if(!e)e=window.event;
  790. var This=e.data.inthis;
  791. if(This.$nowType=="direct") return;
  792. var Dom=$(this).parents(".GooFlow_item");
  793. var id=Dom.attr("id");
  794. This.focusItem(id,true);
  795. var hack=1;
  796. if(navigator.userAgent.indexOf("8.0")!=-1) hack=0;
  797. var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
  798. This.$ghost.css({display:"block",
  799. width:This.$nodeData[id].width+5+"px", height:This.$nodeData[id].height+"px",
  800. top:This.$nodeData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
  801. left:This.$nodeData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:"move"
  802. });
  803. Dom.children("table").clone().prependTo(This.$ghost);
  804. var X,Y;
  805. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
  806. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
  807. var vX=X-This.$nodeData[id].left,vY=Y-This.$nodeData[id].top;
  808. var isMove=false;
  809. document.onmousemove=function(e){
  810. haveDrag=true
  811. if(!e)e=window.event;
  812. var ev=mousePosition(e);
  813. X=ev.x-vX;
  814. Y=ev.y-vY;
  815. if(X<t.left-This.$workArea[0].parentNode.scrollLeft)
  816. X=t.left-This.$workArea[0].parentNode.scrollLeft;
  817. else if(X+This.$workArea[0].parentNode.scrollLeft+This.$nodeData[id].width>t.left+This.$workArea.width())
  818. X=t.left+This.$workArea.width()-This.$workArea[0].parentNode.scrollLeft-This.$nodeData[id].width;
  819. if(Y<t.top-This.$workArea[0].parentNode.scrollTop)
  820. Y=t.top-This.$workArea[0].parentNode.scrollTop;
  821. else if(Y+This.$workArea[0].parentNode.scrollTop+This.$nodeData[id].height>t.top+This.$workArea.height())
  822. Y=t.top+This.$workArea.height()-This.$workArea[0].parentNode.scrollTop-This.$nodeData[id].height;
  823. This.$ghost.css({left:X+hack+"px",top:Y+hack+"px"});
  824. isMove=true;
  825. }
  826. document.onmouseup=function(e){
  827. if(isMove)This.moveNode(id,X+This.$workArea[0].parentNode.scrollLeft-t.left,Y+This.$workArea[0].parentNode.scrollTop-t.top);
  828. This.$ghost.empty().hide();
  829. document.onmousemove=null;
  830. document.onmouseup=null;
  831. }
  832. });
  833. if(!this.$editable) return;
  834. //绑定鼠标覆盖/移出事件
  835. this.$workArea.delegate(".GooFlow_item","mouseenter",{inthis:this},function(e){
  836. if(e.data.inthis.$nowType!="direct") return;
  837. $(this).addClass("item_mark");
  838. });
  839. this.$workArea.delegate(".GooFlow_item","mouseleave",{inthis:this},function(e){
  840. if(e.data.inthis.$nowType!="direct") return;
  841. $(this).removeClass("item_mark");
  842. });
  843. //绑定连线时确定初始点
  844. this.$workArea.delegate(".GooFlow_item","mousedown",{inthis:this},function(e){
  845. // console.log(e.target)
  846. var This=e.data.inthis;
  847. if(This.$nowType!="direct") return;
  848. var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
  849. var X,Y;
  850. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
  851. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
  852. // console.log(X+" "+Y)
  853. This.$workArea.data("lineStart",{"x":X,"y":Y,"id":this.id}).css("cursor","crosshair");
  854. var line=GooFlow.prototype.drawLine("GooFlow_tmp_line",[X,Y],[X,Y],true,true);
  855. This.$draw.appendChild(line);
  856. });
  857. //绑定连线时确定结束点
  858. this.$workArea.delegate(".GooFlow_item","mouseup",{inthis:this},function(e){
  859. var This=e.data.inthis;
  860. if(This.$nowType!="direct") return;
  861. var lineStart=This.$workArea.data("lineStart");
  862. var json={from:lineStart.id,to:this.id,name:""}
  863. if(fromRejectLine){
  864. json.status="reject";
  865. //匿名函数,判断生成rejectline type
  866. if(function(This,json){
  867. var fromNode=This.$nodeData[json.from];
  868. var toNode=This.$nodeData[json.to];
  869. var l = Math.abs(fromNode.top-toNode.top)
  870. var t=Math.abs(fromNode.left-toNode.left)
  871. if(l>t){
  872. return false
  873. }else{
  874. return true}
  875. }(This,json)){
  876. //纵向
  877. json.type="tb";
  878. json.M=Math.abs(This.$nodeData[json.from].left,This.$nodeData[json.to].left)+20;
  879. }else{
  880. //横向
  881. json.type="lr";
  882. json.M=Math.abs(This.$nodeData[json.from].top,This.$nodeData[json.to].top)+20
  883. }
  884. json.name="退回" // 显示在图上的。Lin
  885. }else{
  886. json.status="agree"
  887. }
  888. fromRejectLine=false
  889. // if(lineStart) This.addLine(This.$id+"_line_"+This.$max,json);
  890. if(lineStart) This.addLine(composeId("line"),json);
  891. // This.$max++;
  892. });
  893. //绑定双击编辑事件
  894. // this.$workArea.delegate(".GooFlow_item > .span","dblclick",{inthis:this},function(e){
  895. // var oldTxt=this.innerHTML;
  896. // var This=e.data.inthis;
  897. // var id=this.parentNode.id;
  898. //
  899. // var t=getElCoordinate(This.$workArea[0]);
  900. // This.$textArea.val(oldTxt).css({display:"block",height:$(this).height(),width:100,
  901. // left:t.left+This.$nodeData[id].left-This.$workArea[0].parentNode.scrollLeft-24,
  902. // top:t.top+This.$nodeData[id].top-This.$workArea[0].parentNode.scrollTop+26})
  903. // .data("id",This.$focus).focus();
  904. // This.$workArea.parent().one("mousedown",function(e){
  905. // console.log(This.$textArea.val())
  906. // This.setName(This.$textArea.data("id"),This.$textArea.val(),"node");
  907. // This.$textArea.val("").removeData("id").hide();
  908. // });
  909. // });
  910. this.$workArea.delegate(".ico + td","dblclick",{inthis:this},function(e){
  911. var oldTxt=this.innerHTML;
  912. var This=e.data.inthis;
  913. var id=$(this).parents(".GooFlow_item").attr("id");
  914. // console.log("内部:"+id)
  915. var t=getElCoordinate(This.$workArea[0]);
  916. This.$textArea.val(oldTxt).css({display:"block",width:$(this).width()+24,height:$(this).height(),
  917. left:t.left+24+This.$nodeData[id].left-This.$workArea[0].parentNode.scrollLeft,
  918. top:t.top+2+This.$nodeData[id].top-This.$workArea[0].parentNode.scrollTop})
  919. .data("id",This.$focus).focus();
  920. This.$workArea.parent().one("mousedown",function(e){
  921. // console.log("write:"+This.$textArea.val());
  922. This.setName(This.$textArea.data("id"),This.$textArea.val(),"node");
  923. This.$textArea.val("").removeData("id").hide();
  924. });
  925. });
  926. //绑定结点的删除功能
  927. this.$workArea.delegate(".rs_close","click",{inthis:this},function(e){
  928. if(!e)e=window.event;
  929. e.data.inthis.delNode(e.data.inthis.$focus);
  930. return false;
  931. });
  932. //绑定设置框
  933. this.$workArea.delegate(".rs_control","click",{inthis:this},function(e){
  934. if(!e)e=window.event;
  935. var node=e.data.inthis.$focus
  936. control.show(e.data.inthis.$nodeData[node])
  937. return false;
  938. });
  939. this.$workArea.delegate(".rs_rejectline","mousedown",{inthis:this},function(e){
  940. if(!e)e=window.event;
  941. var This=e.data.inthis;
  942. var nodeId=this.parentNode.parentNode.id;
  943. var lines=This.$lineData;
  944. // 仅允许一条退回线
  945. for(var key in lines){
  946. if(lines[key].from==nodeId&&lines[key].status=="reject"){
  947. alert("退线已存在")
  948. return false
  949. }
  950. }
  951. This.$nowType="direct"
  952. fromRejectLine=true;
  953. this.style.background="red";
  954. var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
  955. var X,Y;
  956. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
  957. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
  958. //console.log(X+" "+Y);
  959. This.$workArea.data("lineStart",{"x":X,"y":Y,"id":nodeId}).css("cursor","crosshair");
  960. var line=GooFlow.prototype.drawLine("GooFlow_tmp_line",[X,Y],[X,Y],true,true);
  961. This.$draw.appendChild(line);
  962. return false;
  963. });
  964. //绑定结点的RESIZE功能
  965. this.$workArea.delegate(".GooFlow_item > div > div[class!=rs_close]","mousedown",{inthis:this},function(e){
  966. if(!e)e=window.event;
  967. var cursor=$(this).css("cursor");
  968. if(cursor=="pointer"){return;}
  969. var This=e.data.inthis;
  970. var id=This.$focus;
  971. This.switchToolBtn("cursor");
  972. e.cancelBubble = true;
  973. e.stopPropagation();
  974. var hack=1;
  975. if(navigator.userAgent.indexOf("8.0")!=-1) hack=0;
  976. var ev=mousePosition(e),t=getElCoordinate(This.$workArea[0]);
  977. This.$ghost.css({display:"block",
  978. width:This.$nodeData[id].width-2+"px", height:This.$nodeData[id].height-2+"px",
  979. top:This.$nodeData[id].top+t.top-This.$workArea[0].parentNode.scrollTop+hack+"px",
  980. left:This.$nodeData[id].left+t.left-This.$workArea[0].parentNode.scrollLeft+hack+"px",cursor:cursor
  981. });
  982. var X,Y;
  983. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft;
  984. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop;
  985. var vX=(This.$nodeData[id].left+This.$nodeData[id].width)-X;
  986. var vY=(This.$nodeData[id].top+This.$nodeData[id].height)-Y;
  987. var isMove=false;
  988. This.$ghost.css("cursor",cursor);
  989. document.onmousemove=function(e){
  990. // console.log("dddddd");
  991. if(typeof This.$nodeData[id] =="undefined"){
  992. document.onmousemove=null;
  993. return;
  994. }
  995. if(!e)e=window.event;
  996. var ev=mousePosition(e);
  997. X=ev.x-t.left+This.$workArea[0].parentNode.scrollLeft-This.$nodeData[id].left+vX;
  998. Y=ev.y-t.top+This.$workArea[0].parentNode.scrollTop-This.$nodeData[id].top+vY;
  999. if(X<24) X=24;
  1000. if(Y<24) Y=24;
  1001. isMove=true;
  1002. switch(cursor){
  1003. case "nw-resize":This.$ghost.css({width:X-2+"px",height:Y-2+"px"});break;
  1004. case "w-resize":This.$ghost.css({width:X-2+"px"});break;
  1005. case "n-resize":This.$ghost.css({height:Y-2+"px"});break;
  1006. }
  1007. }
  1008. document.onmouseup=function(e){
  1009. This.$ghost.hide();
  1010. if(!isMove)return;
  1011. if(!e)e=window.event;
  1012. This.resizeNode(id,This.$ghost.outerWidth(),This.$ghost.outerHeight());
  1013. document.onmousemove=null;
  1014. document.onmouseup=null;
  1015. }
  1016. });
  1017. },
  1018. //获取结点/连线/分组区域的详细信息
  1019. getItemInfo:function(id,type){
  1020. switch(type){
  1021. case "node": return this.$nodeData[id]||null;
  1022. case "line": return this.$lineData[id]||null;
  1023. case "area": return this.$areaData[id]||null;
  1024. }
  1025. },
  1026. //取消所有结点/连线被选定的状态
  1027. blurItem:function(){
  1028. // console.log(this.$focus);
  1029. if(this.$focus!=""){
  1030. var jq=$("#"+this.$focus);
  1031. if(jq.prop("tagName")=="DIV"){
  1032. if(this.onItemBlur!=null&&!this.onItemBlur(id,"node")) return false;
  1033. jq.removeClass("item_focus").children("div:eq(0)").css("display","none");
  1034. }
  1035. else{
  1036. if(this.onItemBlur!=null&&!this.onItemBlur(id,"line")) return false;
  1037. if(GooFlow.prototype.useSVG!=""){
  1038. if(!this.$lineData[this.$focus].marked){
  1039. jq[0].childNodes[1].setAttribute("stroke","#5068AE");
  1040. jq[0].childNodes[1].setAttribute("marker-end","url(#arrow1)");
  1041. }
  1042. }
  1043. else{
  1044. if(!this.$lineData[this.$focus].marked) jq[0].strokeColor="#5068AE";
  1045. }
  1046. this.$lineMove.hide().removeData("type").removeData("tid");
  1047. if(this.$editable) this.$lineOper.hide().removeData("tid");
  1048. }
  1049. }
  1050. this.$focus="";
  1051. return true;
  1052. },
  1053. //选定某个结点/转换线 bool:TRUE决定了要触发选中事件,FALSE则不触发选中事件,多用在程序内部调用。
  1054. focusItem:function(id,bool,blurItem){
  1055. var jq=$("#"+id);
  1056. if(jq.length==0) return;
  1057. if(!blurItem){
  1058. if(!this.blurItem()) return;//先执行"取消选中",如果返回FLASE,则也会阻止选定事件继续进行.
  1059. }
  1060. if(jq.prop("tagName")=="DIV"){
  1061. if(bool&&this.onItemFocus!=null&&!this.onItemFocus(id,"node")) return;
  1062. jq.addClass("item_focus");
  1063. if(this.$editable)jq.children("div:eq(0)").css("display","block");
  1064. this.$workArea.append(jq);
  1065. }
  1066. else{//如果是连接线
  1067. if(this.onItemFocus!=null&&!this.onItemFocus(id,"line")) return;
  1068. if(GooFlow.prototype.useSVG!=""){
  1069. jq[0].childNodes[1].setAttribute("stroke","#ff3300");
  1070. jq[0].childNodes[1].setAttribute("marker-end","url(#arrow2)");
  1071. }
  1072. else jq[0].strokeColor="#ff3300";
  1073. if(!this.$editable) return;
  1074. var x,y,from,to;
  1075. if(GooFlow.prototype.useSVG!=""){
  1076. from=jq.attr("from").split(",");
  1077. to=jq.attr("to").split(",");
  1078. }else{
  1079. var n=jq[0].getAttribute("fromTo").split(",");
  1080. from=[n[0],n[1]];
  1081. to=[n[2],n[3]];
  1082. }
  1083. from[0]=parseInt(from[0],10);
  1084. from[1]=parseInt(from[1],10);
  1085. to[0]=parseInt(to[0],10);
  1086. to[1]=parseInt(to[1],10);
  1087. //var t=getElCoordinate(this.$workArea[0]);
  1088. if(this.$lineData[id].type=="lr"){
  1089. from[0]=this.$lineData[id].M;
  1090. to[0]=from[0];
  1091. this.$lineMove.css({
  1092. width:"5px",height:(to[1]-from[1])*(to[1]>from[1]? 1:-1)+"px",
  1093. left:from[0]-3+"px",
  1094. top:(to[1]>from[1]? from[1]:to[1])+1+"px",
  1095. cursor:"e-resize",display:"block"
  1096. }).data({"type":"lr","tid":id});
  1097. }
  1098. else if(this.$lineData[id].type=="tb"){
  1099. from[1]=this.$lineData[id].M;
  1100. to[1]=from[1];
  1101. this.$lineMove.css({
  1102. width:(to[0]-from[0])*(to[0]>from[0]? 1:-1)+"px",height:"5px",
  1103. left:(to[0]>from[0]? from[0]:to[0])+1+"px",
  1104. top:from[1]-3+"px",
  1105. cursor:"s-resize",display:"block"
  1106. }).data({"type":"tb","tid":id});
  1107. }
  1108. x=(from[0]+to[0])/2-35;
  1109. y=(from[1]+to[1])/2+6;
  1110. this.$lineOper.css({display:"block",left:x+"px",top:y+"px"}).data("tid",id);
  1111. }
  1112. this.$focus=id;
  1113. this.switchToolBtn("cursor");
  1114. },
  1115. //移动结点到一个新的位置
  1116. moveNode:function(id,left,top){
  1117. if(!this.$nodeData[id]) return;
  1118. if(this.onItemMove!=null&&!this.onItemMove(id,"node")) return;
  1119. if(this.$undoStack){
  1120. var paras=[id,this.$nodeData[id].left,this.$nodeData[id].top];
  1121. this.pushOper("moveNode",paras);
  1122. }
  1123. // $(".decisionLine").remove();
  1124. if(left<0) left=0;
  1125. if(top<0) top=0;
  1126. // if(this.$nodeData[id].type=="node"){
  1127. // initDecisionLine($("#" + id), this.$nodeData[id].condition_name.length);
  1128. moveDececisionLine($("#" + id))
  1129. // }
  1130. $("#"+id).css({left:left+"px",top:top+"px"});
  1131. this.$nodeData[id].left=left;
  1132. this.$nodeData[id].top=top;
  1133. //重画转换线
  1134. this.resetLines(id,this.$nodeData[id]);
  1135. },
  1136. //设置结点/连线/分组区域的文字信息
  1137. setName:function(id,name,type){
  1138. var oldName;
  1139. if(type=="node"){
  1140. //如果是结点
  1141. if(!this.$nodeData[id]) return;
  1142. // if(this.$nodeData[id].name==name)return;
  1143. if(this.onItemRename!=null&&!this.onItemRename(id,name,"node")) return;
  1144. oldName=this.$nodeData[id].name;
  1145. this.$nodeData[id].name=name;
  1146. if(this.$nodeData[id].type=="start"||this.$nodeData[id].type=="end"||this.$nodeData[id].type=="node"||this.$nodeData[id].type=="task"||this.$nodeData[id].type=="fork"||this.$nodeData[id].type=="join"||this.$nodeData[id].type=="foreach"||this.$nodeData[id].type=="transmit"){
  1147. this.$nodeDom[id].children(".span").text(name);
  1148. }
  1149. else{
  1150. this.$nodeDom[id].find("td:eq(1)").text(name);
  1151. var hack=0;
  1152. if(navigator.userAgent.indexOf("8.0")!=-1) hack=2;
  1153. var width=this.$nodeDom[id].outerWidth();
  1154. var height=this.$nodeDom[id].outerHeight();
  1155. this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
  1156. this.$nodeData[id].width=width;
  1157. this.$nodeData[id].height=height;
  1158. }
  1159. //重画转换线
  1160. this.resetLines(id,this.$nodeData[id]);
  1161. }
  1162. else if(type=="line"){//如果是线
  1163. if(!this.$lineData[id]) return;
  1164. if(this.$lineData[id].name==name) return;
  1165. if(this.onItemRename!=null&&!this.onItemRename(id,name,"line")) return;
  1166. oldName=this.$lineData[id].name;
  1167. this.$lineData[id].name=name;
  1168. if(GooFlow.prototype.useSVG!=""){
  1169. this.$lineDom[id].childNodes[2].textContent=name;
  1170. }
  1171. else{
  1172. this.$lineDom[id].childNodes[1].innerHTML=name;
  1173. var n=this.$lineDom[id].getAttribute("fromTo").split(",");
  1174. var x;
  1175. if(this.$lineData[id].type!="lr"){
  1176. x=(n[2]-n[0])/2;
  1177. }
  1178. else{
  1179. var Min=n[2]>n[0]? n[0]:n[2];
  1180. if(Min>this.$lineData[id].M) Min=this.$lineData[id].M;
  1181. x=this.$lineData[id].M-Min;
  1182. }
  1183. if(x<0) x=x*-1;
  1184. this.$lineDom[id].childNodes[1].style.left=x-this.$lineDom[id].childNodes[1].offsetWidth/2+4+"px";
  1185. }
  1186. }
  1187. else if(type=="area"){//如果是分组区域
  1188. if(!this.$areaData[id]) return;
  1189. if(this.$areaData[id].name==name) return;
  1190. if(this.onItemRename!=null&&!this.onItemRename(id,name,"area")) return;
  1191. oldName=this.$areaData[id].name;
  1192. this.$areaData[id].name=name;
  1193. this.$areaDom[id].children("label").text(name);
  1194. }
  1195. if(this.$undoStack){
  1196. var paras=[id,oldName,type];
  1197. this.pushOper("setName",paras);
  1198. }
  1199. },
  1200. //设置结点的尺寸,仅支持非开始/结束结点
  1201. resizeNode:function(id,width,height){
  1202. return; // 再增加,不要 resizeNode(。Lin
  1203. if(!this.$nodeData[id]) return;
  1204. if(this.onItemResize!=null&&!this.onItemResize(id,"node")) return;
  1205. if(this.$nodeData[id].type=="start"||this.$nodeData[id].type=="end")return;
  1206. if(this.$undoStack){
  1207. var paras=[id,this.$nodeData[id].width,this.$nodeData[id].height];
  1208. this.pushOper("resizeNode",paras);
  1209. }
  1210. var hack=0;
  1211. if(navigator.userAgent.indexOf("8.0")!=-1) hack=2;
  1212. this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
  1213. width=this.$nodeDom[id].outerWidth()-hack;
  1214. height=this.$nodeDom[id].outerHeight()-hack;
  1215. this.$nodeDom[id].children("table").css({width:width-2+"px",height:height-2+"px"});
  1216. this.$nodeData[id].width=width;
  1217. this.$nodeData[id].height=height;
  1218. //重画转换线
  1219. this.resetLines(id,this.$nodeData[id]);
  1220. },
  1221. //删除结点
  1222. delNode:function(id){
  1223. if(!this.$nodeData[id]) return;
  1224. if(this.$undoStack){
  1225. var paras=[id,this.$nodeData[id]];
  1226. this.pushOper("addNode",paras);
  1227. }
  1228. if(this.onItemDel!=null&&!this.onItemDel(id,"node")) return;
  1229. delete this.$nodeData[id];
  1230. this.$nodeDom[id].remove();
  1231. delete this.$nodeDom[id];
  1232. --this.$nodeCount;
  1233. if(this.$focus==id) this.$focus="";
  1234. for(var k in this.$lineData){
  1235. if(this.$lineData[k].from==id||this.$lineData[k].to==id){
  1236. this.$draw.removeChild(this.$lineDom[k]);
  1237. delete this.$lineData[k];
  1238. delete this.$lineDom[k];
  1239. }
  1240. }
  1241. // $(".decisionLine").remove();
  1242. },
  1243. //设置流程图的名称
  1244. setTitle:function(text){
  1245. this.$title=text;
  1246. if(this.$head) this.$head.children("label").attr("title",text).text(text);
  1247. },
  1248. //载入一组数据
  1249. loadData:function(data){
  1250. this.setTitle(data.title);
  1251. for(var i in data.nodes)
  1252. this.addNode(i,data.nodes[i]);
  1253. for(var j in data.lines)
  1254. this.addLine(j,data.lines[j]);
  1255. for(var k in data.areas)
  1256. this.addArea(k,data.areas[k]);
  1257. // console.log(data.objectKey)
  1258. if(data.objectKey){
  1259. this.$objectKey=data.objectKey
  1260. }
  1261. },
  1262. //用AJAX方式,远程读取一组数据
  1263. //参数para为JSON结构,与JQUERY中$.ajax()方法的传参一样
  1264. loadDataAjax:function(para){
  1265. var This=this;
  1266. $.ajax({
  1267. type:para.type,
  1268. url:para.url,
  1269. dataType:"json",
  1270. data:para.data,
  1271. success: function(msg){
  1272. if(para.dataFilter) para.dataFilter(msg,"json");
  1273. This.loadData(msg);
  1274. if(para.success) para.success(msg);
  1275. },
  1276. error: function(XMLHttpRequest, textStatus, errorThrown){
  1277. if(para.error) para.error(textStatus,errorThrown);
  1278. }
  1279. })
  1280. },
  1281. //把画好的结束导出到一个变量中(其实也可以直接访问GooFlow对象的$nodeData,$lineData,$areaData这三个JSON属性)
  1282. exportData:function(){
  1283. return {nodes:this.$nodeData,lines:this.$lineData,objectKey:this.$objectKey};
  1284. },
  1285. //清空工作区及已载入的数据
  1286. clearData:function(){
  1287. for(var key in this.$nodeData){
  1288. this.delNode(key);
  1289. }
  1290. for(var key in this.$lineData){
  1291. this.delLine(key);
  1292. }
  1293. for(var key in this.$areaData){
  1294. this.delArea(key);
  1295. }
  1296. },
  1297. //销毁自己
  1298. destrory:function(){
  1299. this.$bgDiv.empty();
  1300. this.$lineData=null;
  1301. this.$nodeData=null;
  1302. this.$lineDom=null;
  1303. this.$nodeDom=null;
  1304. this.$areaDom=null;
  1305. this.$areaData=null;
  1306. this.$nodeCount=0;
  1307. this.$areaCount=0;
  1308. this.$areaCount=0;
  1309. },
  1310. ///////////以下为有关画线的方法
  1311. //绘制一条箭头线,并返回线的DOM
  1312. drawLine:function(id,sp,ep,mark,dash){
  1313. var line;
  1314. if(GooFlow.prototype.useSVG!=""){
  1315. line=document.createElementNS("http://www.w3.org/2000/svg","g");
  1316. var hi=document.createElementNS("http://www.w3.org/2000/svg","path");
  1317. var path=document.createElementNS("http://www.w3.org/2000/svg","path");
  1318. if(id!="") line.setAttribute("id",id);
  1319. line.setAttribute("from",sp[0]+","+sp[1]);
  1320. line.setAttribute("to",ep[0]+","+ep[1]);
  1321. hi.setAttribute("visibility","hidden");
  1322. hi.setAttribute("stroke-width",9);
  1323. hi.setAttribute("fill","none");
  1324. hi.setAttribute("stroke","white");
  1325. hi.setAttribute("d","M "+sp[0]+" "+sp[1]+" L "+ep[0]+" "+ep[1]);
  1326. hi.setAttribute("pointer-events","stroke");
  1327. path.setAttribute("d","M "+sp[0]+" "+sp[1]+" L "+ep[0]+" "+ep[1]);
  1328. path.setAttribute("stroke-width",2);
  1329. path.setAttribute("stroke-linecap","round");
  1330. path.setAttribute("fill","none");
  1331. if(dash) path.setAttribute("style", "stroke-dasharray:6,5");
  1332. if(mark){
  1333. path.setAttribute("stroke","#ff3300");
  1334. path.setAttribute("marker-end","url(#arrow2)");
  1335. }
  1336. else{
  1337. path.setAttribute("stroke","#333"); /*线的颜色*/
  1338. path.setAttribute("marker-end","url(#arrow1)");
  1339. }
  1340. line.appendChild(hi);
  1341. line.appendChild(path);
  1342. line.style.cursor="crosshair";
  1343. if(id!=""&&id!="GooFlow_tmp_line"){
  1344. var text=document.createElementNS("http://www.w3.org/2000/svg","text");
  1345. //text.textContent=id;
  1346. line.appendChild(text);
  1347. var x=(ep[0]+sp[0])/2;
  1348. var y=(ep[1]+sp[1])/2;
  1349. text.setAttribute("text-anchor","middle");
  1350. text.setAttribute("x",x);
  1351. text.setAttribute("y",y);
  1352. line.style.cursor="pointer";
  1353. text.style.cursor="text";
  1354. }
  1355. }else{
  1356. line=document.createElement("v:polyline");
  1357. if(id!="") line.id=id;
  1358. //line.style.position="absolute";
  1359. line.points.value=sp[0]+","+sp[1]+" "+ep[0]+","+ep[1];
  1360. line.setAttribute("fromTo",sp[0]+","+sp[1]+","+ep[0]+","+ep[1]);
  1361. line.strokeWeight="1.2";
  1362. line.stroke.EndArrow="Block";
  1363. line.style.cursor="crosshair";
  1364. if(id!=""&&id!="GooFlow_tmp_line"){
  1365. var text=document.createElement("div");
  1366. //text.innerHTML=id;
  1367. line.appendChild(text);
  1368. var x=(ep[0]-sp[0])/2;
  1369. var y=(ep[1]-sp[1])/2;
  1370. if(x<0) x=x*-1;
  1371. if(y<0) y=y*-1;
  1372. text.style.left=x+"px";
  1373. text.style.top=y-6+"px";
  1374. line.style.cursor="pointer";
  1375. }
  1376. if(dash) line.stroke.dashstyle="Dash";
  1377. if(mark) line.strokeColor="#333";
  1378. else line.strokeColor="#333";
  1379. }
  1380. return line;
  1381. },
  1382. //画一条只有两个中点的折线
  1383. drawPoly:function(id,sp,m1,m2,ep,mark){
  1384. var poly,strPath;
  1385. if(GooFlow.prototype.useSVG!=""){
  1386. poly=document.createElementNS("http://www.w3.org/2000/svg","g");
  1387. var hi=document.createElementNS("http://www.w3.org/2000/svg","path");
  1388. var path=document.createElementNS("http://www.w3.org/2000/svg","path");
  1389. if(id!="") poly.setAttribute("id",id);
  1390. poly.setAttribute("from",sp[0]+","+sp[1]);
  1391. poly.setAttribute("to",ep[0]+","+ep[1]);
  1392. hi.setAttribute("visibility","hidden");
  1393. hi.setAttribute("stroke-width",9);
  1394. hi.setAttribute("fill","none");
  1395. hi.setAttribute("stroke","white");
  1396. strPath="M "+sp[0]+" "+sp[1];
  1397. if(m1[0]!=sp[0]||m1[1]!=sp[1])
  1398. strPath+=" L "+m1[0]+" "+m1[1];
  1399. if(m2[0]!=ep[0]||m2[1]!=ep[1])
  1400. strPath+=" L "+m2[0]+" "+m2[1];
  1401. strPath+=" L "+ep[0]+" "+ep[1];
  1402. hi.setAttribute("d",strPath);
  1403. hi.setAttribute("pointer-events","stroke");
  1404. path.setAttribute("d",strPath);
  1405. path.setAttribute("stroke-width",2);
  1406. path.setAttribute("stroke-linecap","round");
  1407. path.setAttribute("fill","none");
  1408. if(mark){
  1409. path.setAttribute("stroke","#333");
  1410. path.setAttribute("marker-end","url(#arrow2)");
  1411. }
  1412. else{
  1413. path.setAttribute("stroke","#333"); /*绘制线的颜色*/
  1414. path.setAttribute("marker-end","url(#arrow1)");
  1415. }
  1416. poly.appendChild(hi);
  1417. poly.appendChild(path);
  1418. var text=document.createElementNS("http://www.w3.org/2000/svg","text");
  1419. //text.textContent=id;
  1420. poly.appendChild(text);
  1421. var x=(m2[0]+m1[0])/2;
  1422. var y=(m2[1]+m1[1])/2 -3; // 增加 -3,避免文字和横向重叠。Lin
  1423. text.setAttribute("text-anchor","middle");
  1424. text.setAttribute("x",x);
  1425. text.setAttribute("y",y);
  1426. text.style.cursor="text";
  1427. poly.style.cursor="pointer";
  1428. }
  1429. else{
  1430. poly=document.createElement("v:Polyline");
  1431. if(id!="") poly.id=id;
  1432. poly.filled="false";
  1433. strPath=sp[0]+","+sp[1];
  1434. if(m1[0]!=sp[0]||m1[1]!=sp[1])
  1435. strPath+=" "+m1[0]+","+m1[1];
  1436. if(m2[0]!=ep[0]||m2[1]!=ep[1])
  1437. strPath+=" "+m2[0]+","+m2[1];
  1438. strPath+=" "+ep[0]+","+ep[1];
  1439. poly.points.value=strPath;
  1440. poly.setAttribute("fromTo",sp[0]+","+sp[1]+","+ep[0]+","+ep[1]);
  1441. poly.strokeWeight="1.2";
  1442. poly.stroke.EndArrow="Block";
  1443. var text=document.createElement("div");
  1444. //text.innerHTML=id;
  1445. poly.appendChild(text);
  1446. var x=(m2[0]-m1[0])/2;
  1447. var y=(m2[1]-m1[1])/2;
  1448. if(x<0) x=x*-1;
  1449. if(y<0) y=y*-1;
  1450. text.style.left=x+"px";
  1451. text.style.top=y-4+"px";
  1452. poly.style.cursor="pointer";
  1453. if(mark) poly.strokeColor="#ff3300";
  1454. else poly.strokeColor="#5068AE"
  1455. }
  1456. return poly;
  1457. },
  1458. //计算两个结点间要连直线的话,连线的开始坐标和结束坐标
  1459. calcStartEnd:function(n1,n2){
  1460. var X_1,Y_1,X_2,Y_2;
  1461. //X判断:
  1462. var x11=n1.left,x12=n1.left+n1.width;
  1463. var x21=n2.left,x22=n2.left+n2.width;
  1464. //结点2在结点1左边
  1465. if(x11>=x22){
  1466. X_1=x11;X_2=x22;
  1467. if(n1.type=="node"){X_1=X_1+10}
  1468. }
  1469. //结点2在结点1右边
  1470. else if(x12<=x21){
  1471. X_1=x12;X_2=x21;
  1472. if(n1.type=="node"){X_1=X_1-10}
  1473. }
  1474. //结点2在结点1水平部分重合
  1475. else if(x11<=x21&&x12>=x21&&x12<=x22){
  1476. X_1=(x12+x21)/2;X_2=X_1;
  1477. }
  1478. else if(x11>=x21&&x12<=x22){
  1479. X_1=(x11+x12)/2;X_2=X_1;
  1480. }
  1481. else if(x21>=x11&&x22<=x12){
  1482. X_1=(x21+x22)/2;X_2=X_1;
  1483. }
  1484. else if(x11<=x22&&x12>=x22){
  1485. X_1=(x11+x22)/2;X_2=X_1;
  1486. }
  1487. //Y判断:
  1488. var y11=n1.top,y12=n1.top+n1.height;
  1489. var y21=n2.top,y22=n2.top+n2.height;
  1490. //结点2在结点1上边
  1491. if(y11>=y22){
  1492. Y_1=y11;Y_2=y22;
  1493. if(n1.type=="node"){Y_1=Y_1+10}
  1494. }
  1495. //结点2在结点1下边
  1496. else if(y12<=y21){
  1497. Y_1=y12;Y_2=y21;
  1498. if(n1.type=="type"){Y_1=Y_1-10}
  1499. }
  1500. //结点2在结点1垂直部分重合
  1501. else if(y11<=y21&&y12>=y21&&y12<=y22){
  1502. Y_1=(y12+y21)/2;Y_2=Y_1;
  1503. }
  1504. else if(y11>=y21&&y12<=y22){
  1505. Y_1=(y11+y12)/2;Y_2=Y_1;
  1506. }
  1507. else if(y21>=y11&&y22<=y12){
  1508. Y_1=(y21+y22)/2;Y_2=Y_1;
  1509. }
  1510. else if(y11<=y22&&y12>=y22){
  1511. Y_1=(y11+y22)/2;Y_2=Y_1;
  1512. }
  1513. return {"start":[X_1,Y_1],"end":[X_2,Y_2]};
  1514. },
  1515. //计算两个结点间要连折线的话,连线的所有坐标
  1516. calcPolyPoints:function(n1,n2,type,M){
  1517. //开始/结束两个结点的中心
  1518. var SP={x:n1.left+n1.width/2,y:n1.top+n1.height/2};
  1519. var EP={x:n2.left+n2.width/2,y:n2.top+n2.height/2};
  1520. var sp=[],m1=[],m2=[],ep=[];
  1521. //如果是允许中段可左右移动的折线,则参数M为可移动中段线的X坐标
  1522. //粗略计算起始点
  1523. sp=[SP.x,SP.y];
  1524. ep=[EP.x,EP.y];
  1525. if(type=="lr"){
  1526. //粗略计算2个中点
  1527. m1=[M,SP.y];
  1528. m2=[M,EP.y];
  1529. //再具体分析修改开始点和中点1
  1530. if(m1[0]>n1.left&&m1[0]<n1.left+n1.width){
  1531. m1[1]=(SP.y>EP.y? n1.top:n1.top+n1.height);
  1532. sp[0]=m1[0];sp[1]=m1[1];
  1533. }
  1534. else{
  1535. sp[0]=(m1[0]<n1.left? n1.left:n1.left+n1.width)
  1536. }
  1537. //再具体分析中点2和结束点
  1538. if(m2[0]>n2.left&&m2[0]<n2.left+n2.width){
  1539. m2[1]=(SP.y>EP.y? n2.top+n2.height:n2.top);
  1540. ep[0]=m2[0];ep[1]=m2[1];
  1541. }
  1542. else{
  1543. ep[0]=(m2[0]<n2.left? n2.left:n2.left+n2.width)
  1544. }
  1545. }
  1546. //如果是允许中段可上下移动的折线,则参数M为可移动中段线的Y坐标
  1547. else if(type=="tb"){
  1548. //粗略计算2个中点
  1549. m1=[SP.x,M];
  1550. m2=[EP.x,M];
  1551. //再具体分析修改开始点和中点1
  1552. if(m1[1]>n1.top&&m1[1]<n1.top+n1.height){
  1553. m1[0]=(SP.x>EP.x? n1.left:n1.left+n1.width);
  1554. sp[0]=m1[0];sp[1]=m1[1];
  1555. }
  1556. else{
  1557. sp[1]=(m1[1]<n1.top? n1.top:n1.top+n1.height)
  1558. }
  1559. //再具体分析中点2和结束点
  1560. if(m2[1]>n2.top&&m2[1]<n2.top+n2.height){
  1561. m2[0]=(SP.x>EP.x? n2.left+n2.width:n2.left);
  1562. ep[0]=m2[0];ep[1]=m2[1];
  1563. }
  1564. else{
  1565. ep[1]=(m2[1]<n2.top? n2.top:n2.top+n2.height);
  1566. }
  1567. }
  1568. return {start:sp,m1:m1,m2:m2,end:ep};
  1569. },
  1570. //初始化折线中段的X/Y坐标,mType='rb'时为X坐标,mType='tb'时为Y坐标
  1571. getMValue:function(n1,n2,mType){
  1572. if(mType=="lr"){
  1573. return (n1.left+n1.width/2+n2.left+n2.width/2)/2;
  1574. }
  1575. else if(mType=="tb"){
  1576. return (n1.top+n1.height/2+n2.top+n2.height/2)/2;
  1577. }
  1578. },
  1579. //增加一条线
  1580. addLine:function(id,json){
  1581. // console.log(json)
  1582. if(this.onItemAdd!=null&&!this.onItemAdd(id,"line"))return;
  1583. if(this.$undoStack){
  1584. this.pushOper("delLine",[id]);
  1585. }
  1586. for(var key in this.$lineData){
  1587. if(this.$lineData[key].id==id){
  1588. console.log("same id")
  1589. // this.$max++
  1590. // console.log(arguments.callee)
  1591. // id=this.$id+"_line_"+this.$max;
  1592. // id=composeId("line")
  1593. return;
  1594. // continue
  1595. }
  1596. }
  1597. // //计算$max最大值,防止ID重复
  1598. // var IDMAX=parseInt(id.replace(/[^0-9]/ig,""));
  1599. // if(this.$max<IDMAX){
  1600. // this.$max=IDMAX+1
  1601. // };
  1602. // json.id=id;
  1603. //
  1604. $(".rs_rejectline").css("background","")
  1605. var n1=null,n2=null;//获取开始/结束结点的数据
  1606. if(json.from==json.to) return;
  1607. //避免两个节点间有两条以下直接连线
  1608. //可以有双向线 线只有一条
  1609. var fromcount=0;
  1610. var tocount=0;
  1611. var rejectcount=0
  1612. for(var k in this.$lineData){
  1613. //普通线
  1614. if(json.from==this.$lineData[k].from&&json.to==this.$lineData[k].to&&this.$lineData[k].status!="reject"){
  1615. fromcount++
  1616. }
  1617. // 进入线
  1618. if(json.to==this.$lineData[k].from&&json.from==this.$lineData[k].to){
  1619. tocount++
  1620. }
  1621. // reject线
  1622. if(json.from==this.$lineData[k].from&&this.$lineData[k].status=="reject"){
  1623. rejectcount++
  1624. }
  1625. // if((json.from==this.$lineData[k].from&&json.to==this.$lineData[k].to)
  1626. // ||(json.from==this.$lineData[k].to&&json.to==this.$lineData[k].from))
  1627. // return;
  1628. }
  1629. // console.log("from\to\reject line count"+fromcount+" "+tocount+" "+rejectcount);
  1630. //已存在普通线
  1631. //新增普通线只限一条
  1632. if(fromcount>=1&&json.status!="reject"){alert("普通线已存在"); return}
  1633. //已存在reject线
  1634. //新增 退回线只限一条
  1635. if(rejectcount>=1&&json.status=="reject"){alert("退回线已存在");return }
  1636. // console.log(json)
  1637. var n1=this.$nodeData[json.from],n2=this.$nodeData[json.to];//获取开始/结束结点的数据
  1638. if(!n1||!n2) return;
  1639. var res;
  1640. if(json.type&&json.type!="sl")
  1641. res=GooFlow.prototype.calcPolyPoints(n1,n2,json.type,json.M);
  1642. else
  1643. res=GooFlow.prototype.calcStartEnd(n1,n2);
  1644. if(!res) return;
  1645. this.$lineData[id]={};
  1646. if(json.type){
  1647. this.$lineData[id].type=json.type;
  1648. this.$lineData[id].M=json.M;
  1649. }
  1650. else this.$lineData[id].type="sl";//默认为直线
  1651. this.$lineData[id].status=json.status;
  1652. this.$lineData[id].from=json.from;
  1653. this.$lineData[id].to=json.to;
  1654. this.$lineData[id].name=json.name;
  1655. //防止ID重复
  1656. // var IDMAX=parseInt(id.replace(/[^0-9]/ig,""));
  1657. // if(this.$max<IDMAX){
  1658. // this.$max=IDMAX+1
  1659. // };
  1660. this.$lineData[id].id=id;
  1661. //this.$lineData[id].other={};
  1662. //this.$lineData[id].other.key="";
  1663. //this.$lineData[id].other.transition="";
  1664. //this.$lineData[id].other.message="";
  1665. //this.$lineData[id].other.service="";
  1666. //this.$lineData[id].other.dest="";
  1667. //this.$lineData[id].other.content=""
  1668. if(json.marked) this.$lineData[id].marked=json.marked;
  1669. else this.$lineData[id].marked=false;
  1670. if(this.$lineData[id].type=="sl")
  1671. this.$lineDom[id]=GooFlow.prototype.drawLine(id,res.start,res.end,json.mark);
  1672. else
  1673. this.$lineDom[id]=GooFlow.prototype.drawPoly(id,res.start,res.m1,res.m2,res.end,json.mark);
  1674. this.$draw.appendChild(this.$lineDom[id]);
  1675. if(GooFlow.prototype.useSVG==""){
  1676. this.$lineDom[id].childNodes[1].innerHTML=json.name;
  1677. if(this.$lineData[id].type!="sl"){
  1678. var Min=(res.start[0]>res.end[0]? res.end[0]:res.start[0]);
  1679. if(Min>res.m2[0]) Min=res.m2[0];
  1680. if(Min>res.m1[0]) Min=res.m1[0];
  1681. this.$lineDom[i].childNodes[1].style.left = (res.m2[0]+res.m1[0])/2-Min-this.$lineDom[id].childNodes[1].offsetWidth/2+4;
  1682. Min=(res.start[1]>res.end[1]? res.end[1]:res.start[1]);
  1683. if(Min>res.m2[1]) Min=res.m2[1];
  1684. if(Min>res.m1[1]) Min=res.m1[1];
  1685. this.$lineDom[id].childNodes[1].style.top = (res.m2[1]+res.m1[1])/2-Min-this.$lineDom[id].childNodes[1].offsetHeight/2;
  1686. }else
  1687. this.$lineDom[id].childNodes[1].style.left=
  1688. ((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[id].childNodes[1].offsetWidth)/2+4;
  1689. }
  1690. else this.$lineDom[id].childNodes[2].textContent=json.name;
  1691. ++this.$lineCount;
  1692. },
  1693. //重构所有连向某个结点的线的显示,传参结构为$nodeData数组的一个单元结构
  1694. resetLines:function(id,node){
  1695. for(var i in this.$lineData){
  1696. var other=null;//获取结束/开始结点的数据
  1697. var res;
  1698. if(this.$lineData[i].from==id){//找结束点
  1699. other=this.$nodeData[this.$lineData[i].to]||null;
  1700. if(other==null) continue;
  1701. if(this.$lineData[i].type=="sl")
  1702. res=GooFlow.prototype.calcStartEnd(node,other);
  1703. else
  1704. res=GooFlow.prototype.calcPolyPoints(node,other,this.$lineData[i].type,this.$lineData[i].M)
  1705. if(!res) break;
  1706. }
  1707. else if(this.$lineData[i].to==id){//找开始点
  1708. other=this.$nodeData[this.$lineData[i].from]||null;
  1709. if(other==null) continue;
  1710. if(this.$lineData[i].type=="sl")
  1711. res=GooFlow.prototype.calcStartEnd(other,node);
  1712. else
  1713. res=GooFlow.prototype.calcPolyPoints(other,node,this.$lineData[i].type,this.$lineData[i].M);
  1714. if(!res) break;
  1715. }
  1716. if(other==null) continue;
  1717. this.$draw.removeChild(this.$lineDom[i]);
  1718. if(this.$lineData[i].type=="sl"){
  1719. this.$lineDom[i]=GooFlow.prototype.drawLine(i,res.start,res.end,this.$lineData[i].marked);
  1720. }
  1721. else{
  1722. this.$lineDom[i]=GooFlow.prototype.drawPoly(i,res.start,res.m1,res.m2,res.end,this.$lineData[i].marked);
  1723. }
  1724. this.$draw.appendChild(this.$lineDom[i]);
  1725. if(GooFlow.prototype.useSVG==""){
  1726. this.$lineDom[i].childNodes[1].innerHTML=this.$lineData[i].name;
  1727. if(this.$lineData[i].type!="sl"){
  1728. var Min=(res.start[0]>res.end[0]? res.end[0]:res.start[0]);
  1729. if(Min>res.m2[0]) Min=res.m2[0];
  1730. if(Min>res.m1[0]) Min=res.m1[0];
  1731. this.$lineDom[i].childNodes[1].style.left = (res.m2[0]+res.m1[0])/2-Min-this.$lineDom[i].childNodes[1].offsetWidth/2+4;
  1732. Min=(res.start[1]>res.end[1]? res.end[1]:res.start[1]);
  1733. if(Min>res.m2[1]) Min=res.m2[1];
  1734. if(Min>res.m1[1]) Min=res.m1[1];
  1735. this.$lineDom[i].childNodes[1].style.top = (res.m2[1]+res.m1[1])/2-Min-this.$lineDom[i].childNodes[1].offsetHeight/2-4;
  1736. }else
  1737. this.$lineDom[i].childNodes[1].style.left=
  1738. ((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[i].childNodes[1].offsetWidth)/2+4;
  1739. }
  1740. else this.$lineDom[i].childNodes[2].textContent=this.$lineData[i].name;
  1741. }
  1742. },
  1743. //重新设置连线的样式 newType= "sl":直线, "lr":中段可左右移动型折线, "tb":中段可上下移动型折线
  1744. setLineType:function(id,newType){
  1745. if(!newType||newType==null||newType==""||newType==this.$lineData[id].type) return false;
  1746. if(this.onLineSetType!=null&&!this.onLineSetType(id,newType)) return;
  1747. if(this.$undoStack){
  1748. var paras=[id,this.$lineData[id].type];
  1749. this.pushOper("setLineType",paras);
  1750. if(this.$lineData[id].type!="sl"){
  1751. var para2=[id,this.$lineData[id].M];
  1752. this.pushOper("setLineM",para2);
  1753. }
  1754. }
  1755. var from=this.$lineData[id].from;
  1756. var to=this.$lineData[id].to;
  1757. this.$lineData[id].type=newType;
  1758. var res;
  1759. //如果是变成折线
  1760. if(newType!="sl"){
  1761. var res=GooFlow.prototype.calcPolyPoints(this.$nodeData[from],this.$nodeData[to],this.$lineData[id].type,this.$lineData[id].M);
  1762. this.setLineM(id,this.getMValue(this.$nodeData[from],this.$nodeData[to],newType),true);
  1763. }
  1764. //如果是变回直线
  1765. else{
  1766. delete this.$lineData[id].M;
  1767. this.$lineMove.hide().removeData("type").removeData("tid");
  1768. res=GooFlow.prototype.calcStartEnd(this.$nodeData[from],this.$nodeData[to]);
  1769. if(!res) return;
  1770. this.$draw.removeChild(this.$lineDom[id]);
  1771. this.$lineDom[id]=GooFlow.prototype.drawLine(id,res.start,res.end,this.$lineData[id].marked||this.$focus==id);
  1772. this.$draw.appendChild(this.$lineDom[id]);
  1773. if(GooFlow.prototype.useSVG==""){
  1774. this.$lineDom[id].childNodes[1].innerHTML=this.$lineData[id].name;
  1775. this.$lineDom[id].childNodes[1].style.left=
  1776. ((res.end[0]-res.start[0])*(res.end[0]>res.start[0]? 1:-1)-this.$lineDom[id].childNodes[1].offsetWidth)/2+4;
  1777. }
  1778. else
  1779. this.$lineDom[id].childNodes[2].textContent=this.$lineData[id].name;
  1780. }
  1781. if(this.$focus==id){
  1782. this.focusItem(id);
  1783. }
  1784. },
  1785. //设置折线中段的X坐标值(可左右移动时)或Y坐标值(可上下移动时)
  1786. setLineM:function(id,M,noStack){
  1787. if(!this.$lineData[id]||M<0||!this.$lineData[id].type||this.$lineData[id].type=="sl") return false;
  1788. if(this.onLineMove!=null&&!this.onLineMove(id,M)) return false;
  1789. if(this.$undoStack&&!noStack){
  1790. var paras=[id,this.$lineData[id].M];
  1791. this.pushOper("setLineM",paras);
  1792. }
  1793. var from=this.$lineData[id].from;
  1794. var to=this.$lineData[id].to;
  1795. this.$lineData[id].M=M;
  1796. var ps=GooFlow.prototype.calcPolyPoints(this.$nodeData[from],this.$nodeData[to],this.$lineData[id].type,this.$lineData[id].M);
  1797. this.$draw.removeChild(this.$lineDom[id]);
  1798. this.$lineDom[id]=GooFlow.prototype.drawPoly(id,ps.start,ps.m1,ps.m2,ps.end,this.$lineData[id].marked||this.$focus==id);
  1799. this.$draw.appendChild(this.$lineDom[id]);
  1800. if(GooFlow.prototype.useSVG==""){
  1801. this.$lineDom[id].childNodes[1].innerHTML=this.$lineData[id].name;
  1802. var Min=(ps.start[0]>ps.end[0]? ps.end[0]:ps.start[0]);
  1803. if(Min>ps.m2[0]) Min=ps.m2[0];
  1804. if(Min>ps.m1[0]) Min=ps.m1[0];
  1805. this.$lineDom[id].childNodes[1].style.left = (ps.m2[0]+ps.m1[0])/2-Min-this.$lineDom[id].childNodes[1].offsetWidth/2+4;
  1806. Min=(ps.start[1]>ps.end[1]? ps.end[1]:ps.start[1]);
  1807. if(Min>ps.m2[1]) Min=ps.m2[1];
  1808. if(Min>ps.m1[1]) Min=ps.m1[1];
  1809. this.$lineDom[id].childNodes[1].style.top = (ps.m2[1]+ps.m1[1])/2-Min-this.$lineDom[id].childNodes[1].offsetHeight/2-4;
  1810. }
  1811. else this.$lineDom[id].childNodes[2].textContent=this.$lineData[id].name;
  1812. },
  1813. //删除转换线
  1814. delLine:function(id){
  1815. if(!this.$lineData[id]) return;
  1816. if(this.onItemDel!=null&&!this.onItemDel(id,"node")) return;
  1817. /// 增加,把被删除的线放回分支节点的 condition_name 数组里 -- 原,删除后,那个脚就不见了。Lin
  1818. // "退回" 线,没有 .condition_name
  1819. var line = this.$lineData[id];
  1820. if (line.name && (line.name != "退回"))
  1821. demo.$nodeData[line.from].condition_name.push(line.name);
  1822. ///
  1823. if(this.$undoStack){
  1824. var paras=[id,this.$lineData[id]];
  1825. this.pushOper("addLine",paras);
  1826. }
  1827. this.$draw.removeChild(this.$lineDom[id]);
  1828. delete this.$lineData[id];
  1829. delete this.$lineDom[id];
  1830. if(this.$focus==id) this.$focus="";
  1831. --this.$lineCount;
  1832. },
  1833. //用颜色标注/取消标注一个结点或转换线,常用于显示重点或流程的进度。
  1834. //这是一个在编辑模式中无用,但是在纯浏览模式中非常有用的方法,实际运用中可用于跟踪流程的进度。
  1835. markItem:function(id,type,mark){
  1836. if(type=="node"){
  1837. if(!this.$nodeData[id]) return;
  1838. if(this.onItemMark!=null&&!this.onItemMark(id,"node",mark)) return;
  1839. this.$nodeData[id].marked=mark||false;
  1840. if(mark) this.$nodeDom[id].addClass("item_mark");
  1841. else this.$nodeDom[id].removeClass("item_mark");
  1842. }else if(type=="line"){
  1843. if(!this.$lineData[id]) return;
  1844. if(this.onItemMark!=null&&!this.onItemMark(id,"line",mark)) return;
  1845. this.$lineData[id].marked=mark||false;
  1846. if(GooFlow.prototype.useSVG!=""){
  1847. if(mark){
  1848. this.$nodeDom[id].childNodes[1].setAttribute("stroke","#ff3300");
  1849. this.$nodeDom[id].childNodes[1].setAttribute("marker-end","url(#arrow2)");
  1850. }else{
  1851. this.$nodeDom[id].childNodes[1].setAttribute("stroke","#5068AE");
  1852. this.$nodeDom[id].childNodes[1].setAttribute("marker-end","url(#arrow1)");
  1853. }
  1854. }else{
  1855. if(mark) this.$nodeDom[id].strokeColor="#ff3300";
  1856. else this.$nodeDom[id].strokeColor="#5068AE"
  1857. }
  1858. }
  1859. if(this.$undoStatck){
  1860. var paras=[id,type,!mark];
  1861. this.pushOper("markItem",paras);
  1862. }
  1863. },
  1864. ////////////////////////以下为区域分组块操作
  1865. moveArea:function(id,left,top){
  1866. if(!this.$areaData[id]) return;
  1867. if(this.onItemMove!=null&&!this.onItemMove(id,"area")) return;
  1868. if(this.$undoStack){
  1869. var paras=[id,this.$areaData[id].left,this.$areaData[id].top];
  1870. this.pushOper("moveNode",paras);
  1871. }
  1872. if(left<0) left=0;
  1873. if(top<0) top=0;
  1874. $("#"+id).css({left:left+"px",top:top+"px"});
  1875. this.$areaData[id].left=left;
  1876. this.$areaData[id].top=top;
  1877. },
  1878. //删除区域分组
  1879. delArea:function(id){
  1880. if(!this.$areaData[id]) return;
  1881. if(this.$undoStack){
  1882. var paras=[id,this.$areaData[id]];
  1883. this.pushOper("addArea",paras);
  1884. }
  1885. if(this.onItemDel!=null&&!this.onItemDel(id,"node")) return;
  1886. delete this.$areaData[id];
  1887. this.$areaDom[id].remove();
  1888. delete this.$areaDom[id];
  1889. --this.$areaCount;
  1890. },
  1891. //设置区域分组的颜色
  1892. setAreaColor:function(id,color){
  1893. if(!this.$areaData[id]) return;
  1894. if(this.$undoStack){
  1895. var paras=[id,this.$areaData[id].color];
  1896. this.pushOper("setAreaColor",paras);
  1897. }
  1898. if(color=="red"||color=="yellow"||color=="blue"||color=="green"){
  1899. this.$areaDom[id].removeClass("area_"+this.$areaData[id].color).addClass("area_"+color);
  1900. this.$areaData[id].color=color;
  1901. }
  1902. },
  1903. //设置区域分块的尺寸
  1904. resizeArea:function(id,width,height){
  1905. if(!this.$areaData[id]) return;
  1906. if(this.onItemResize!=null&&!this.onItemResize(id,"area")) return;
  1907. if(this.$undoStack){
  1908. var paras=[id,this.$areaData[id].width,this.$areaData[id].height];
  1909. this.pushOper("resizeArea",paras);
  1910. }
  1911. var hack=0;
  1912. if(navigator.userAgent.indexOf("8.0")!=-1) hack=2;
  1913. this.$areaDom[id].children(".bg").css({width:width-2+"px",height:height-2+"px"});
  1914. width=this.$areaDom[id].outerWidth();
  1915. height=this.$areaDom[id].outerHeight();
  1916. this.$areaDom[id].children("bg").css({width:width-2+"px",height:height-2+"px"});
  1917. this.$areaData[id].width=width;
  1918. this.$areaData[id].height=height;
  1919. },
  1920. addArea:function(id,json){
  1921. if(this.onItemAdd!=null&&!this.onItemAdd(id,"area"))return;
  1922. if(this.$undoStack){
  1923. this.pushOper("delArea",[id]);
  1924. }
  1925. this.$areaDom[id]=$("<div id='"+id+"' class='GooFlow_area area_"+json.color+"' style='top:"+json.top+"px;left:"+json.left+"px'><div class='bg' style='width:"+(json.width-2)+"px;height:"+(json.height-2)+"px'></div>"
  1926. +"<label>"+json.name+"</label><b></b><div><div class='rs_bottom'></div><div class='rs_right'></div><div class='rs_rb'></div><div class='rs_close'></div></div></div>");
  1927. this.$areaData[id]=json;
  1928. this.$group.append(this.$areaDom[id]);
  1929. ++this.$areaCount;
  1930. }
  1931. }
  1932. //生成线和节点的id
  1933. function composeId(type){
  1934. var curmax=0;//最大值
  1935. var tempNum=0;
  1936. // id.replace(/[^0-9]/ig,"")
  1937. for(key in demo.$lineData){
  1938. tempNum=parseInt(key.replace(/[^0-9]/ig,"") );
  1939. if(tempNum>=curmax){
  1940. curmax=tempNum;
  1941. }
  1942. }
  1943. for(key in demo.$nodeData){
  1944. tempNum=parseInt(key.replace(/[^0-9]/ig,""));
  1945. if(tempNum>=curmax){
  1946. curmax=tempNum;
  1947. }
  1948. }
  1949. var jsonData=document.getElementById("jsonData").innerHTML;
  1950. var version=document.getElementById("version").value;
  1951. if(jsonData!=""){
  1952. jsonData=eval("("+jsonData+")")
  1953. if(jsonData.objectKey){
  1954. for(var i=0;i<jsonData.objectKey.length;i++){
  1955. var nodes=jsonData.objectKey[i].nodes
  1956. // console.log(nodes)
  1957. for(var key in nodes){
  1958. tempNum=parseInt(key.replace(/[^0-9]/ig,""));
  1959. if(tempNum>=curmax&&jsonData.objectKey[i].version!=version){
  1960. curmax=tempNum;
  1961. }
  1962. }
  1963. var lines=jsonData.objectKey[i].lines
  1964. // console.log(lines)
  1965. if(tempNum>=curmax&&jsonData.objectKey[i].version!=version){
  1966. for(var key in lines){
  1967. curmax=tempNum;
  1968. }
  1969. }
  1970. }
  1971. }
  1972. }
  1973. demo.$max=curmax
  1974. demo.$max++
  1975. var num=demo.$max
  1976. var result= type+"_"+num
  1977. console.log("生成唯一ID: "+result);
  1978. return result;
  1979. }
  1980. //识别当前是否来自退回线
  1981. var fromRejectLine=false
  1982. //将此类的构造函数加入至JQUERY对象中
  1983. jQuery.extend({
  1984. createGooFlow:function(bgDiv,property){
  1985. return new GooFlow(bgDiv,property);
  1986. }
  1987. });