You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1909 rivejä
93 KiB

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