mirror of
https://gitee.com/dotnetchina/OpenAuth.Net.git
synced 2025-05-12 00:28:05 +08:00
2280 lines
122 KiB
JavaScript
2280 lines
122 KiB
JavaScript
layui.define("jquery",
|
||
function(exports) {
|
||
var jQuery = layui.jquery,
|
||
$ = layui.jquery;
|
||
|
||
//定义一个区域图类:
|
||
function GooFlow(bgDiv, property) {
|
||
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 = "";
|
||
else GooFlow.prototype.useSVG = "1";
|
||
//初始化区域图的对象
|
||
this.$id = bgDiv.attr("id");
|
||
this.$bgDiv = bgDiv; //最父框架的DIV
|
||
this.$bgDiv.addClass("GooFlow");
|
||
var width = (property.width || 800) - 2;
|
||
var height = (property.height || 500) - 2;
|
||
this.$bgDiv.css({ width: width + "px", height: height + "px" });
|
||
this.$tool = null; //左侧工具栏对象
|
||
this.$head = null; //顶部标签及工具栏按钮
|
||
this.$title = "newFlow_1"; //流程图的名称
|
||
this.$nodeRemark = {}; //每一种结点或按钮的说明文字,JSON格式,key为类名,value为用户自定义文字说明
|
||
this.$nowType = "cursor"; //当前要绘制的对象类型
|
||
this.$lineData = {};
|
||
this.$lineCount = 0;
|
||
this.$nodeData = {};
|
||
this.$nodeCount = 0;
|
||
this.$areaData = {};
|
||
this.$areaCount = 0;
|
||
this.$lineDom = {};
|
||
this.$nodeDom = {};
|
||
this.$areaDom = {};
|
||
this.$max = property.initNum || 1; //计算默认ID值的起始SEQUENCE
|
||
this.$focus = ""; //当前被选定的结点/转换线ID,如果没选中或者工作区被清空,则为""
|
||
this.$cursor = "default"; //鼠标指针在工作区内的样式
|
||
this.$editable = false; //工作区是否可编辑
|
||
this.$deletedItem = {}; //在流程图的编辑操作中被删除掉的元素ID集合,元素ID为KEY,元素类型(node,line.area)为VALUE
|
||
var headHeight = 0;
|
||
var tmp = "";
|
||
if (property.haveHead) {
|
||
tmp = "<div class='GooFlow_head'><label title='" +
|
||
(property.initLabelText || "newFlow_1") +
|
||
"'>" +
|
||
(property.initLabelText || "newFlow_1") +
|
||
"</label>";
|
||
for (var x = 0; x < property.headBtns.length; ++x) {
|
||
tmp += "<a class='GooFlow_head_btn'><b class='ico_" + property.headBtns[x] + "'></b></a>"
|
||
}
|
||
tmp += "</div>";
|
||
this.$head = $(tmp);
|
||
this.$bgDiv.append(this.$head);
|
||
headHeight = 24;
|
||
//以下是当工具栏按钮被点击时触发的事件自定义(虚函数),格式为function(),因为可直接用THIS操作对象本身,不用传参;用户可自行重定义:
|
||
this.onBtnNewClick = null; //新建流程图按钮被点中
|
||
this.onBtnOpenClick = null; //打开流程图按钮定义
|
||
this.onBtnSaveClick = null; //保存流程图按钮定义
|
||
this.onFreshClick = null; //重载流程图按钮定义
|
||
if (property.headBtns)
|
||
this.$head.on("click",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (!e) e = window.event;
|
||
var tar = e.target;
|
||
if (tar.tagName == "DIV" || tar.tagName == "SPAN") return;
|
||
else if (tar.tagName == "a") tar = tar.childNode[0];
|
||
var This = e.data.inthis;
|
||
//定义顶部操作栏按钮的事件
|
||
switch ($(tar).attr("class")) {
|
||
case "ico_new":
|
||
if (This.onBtnNewClick != null) This.onBtnNewClick();
|
||
break;
|
||
case "ico_open":
|
||
if (This.onBtnOpenClick != null) This.onBtnOpenClick();
|
||
break;
|
||
case "ico_save":
|
||
if (This.onBtnSaveClick != null) This.onBtnSaveClick();
|
||
break;
|
||
case "ico_undo":
|
||
This.undo();
|
||
break;
|
||
case "ico_redo":
|
||
This.redo();
|
||
break;
|
||
case "ico_reload":
|
||
if (This.onFreshClick != null) This.onFreshClick();
|
||
break;
|
||
}
|
||
});
|
||
}
|
||
var toolWidth = 0;
|
||
if (property.haveTool) {
|
||
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>");
|
||
this.$tool = this.$bgDiv.find(".GooFlow_tool div");
|
||
//未加代码:加入绘图工具按钮
|
||
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>");
|
||
if (property.toolBtns && property.toolBtns.length > 0) {
|
||
tmp = "<span/>";
|
||
for (var i = 0; i < property.toolBtns.length; ++i) {
|
||
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>"; //加入自定义按钮
|
||
}
|
||
this.$tool.append(tmp);
|
||
}
|
||
//加入区域划分框工具开关按钮
|
||
if (property.haveGroup)
|
||
this.$tool.append("<span/><a type='group' class='GooFlow_tool_btn' id='" +
|
||
this.$id +
|
||
"_btn_group'><b class='ico_group'/></a>");
|
||
toolWidth = 31;
|
||
this.$nowType = "cursor";
|
||
//绑定各个按钮的点击事件
|
||
this.$tool.on("click",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (!e) e = window.event;
|
||
var tar;
|
||
switch (e.target.tagName) {
|
||
case "SPAN":
|
||
return false;
|
||
case "DIV":
|
||
return false;
|
||
case "B":
|
||
tar = e.target.parentNode;
|
||
break;
|
||
case "A":
|
||
tar = e.target;
|
||
};
|
||
var type = $(tar).attr("type");
|
||
e.data.inthis.switchToolBtn(type);
|
||
return false;
|
||
});
|
||
this.$editable = true; //只有具有工具栏时可编辑
|
||
}
|
||
width = width - toolWidth - 8;
|
||
height = height;
|
||
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>");
|
||
this.$workArea = $("<div class='GooFlow_work_inner' style='width:" +
|
||
width * 3 +
|
||
"px;height:" +
|
||
height * 3 +
|
||
"px'></div>")
|
||
.attr({
|
||
"unselectable": "on",
|
||
"onselectstart": 'return false',
|
||
"onselect": 'document.selection.empty()'
|
||
});
|
||
this.$bgDiv.children(".GooFlow_work").append(this.$workArea);
|
||
this.$draw = null; //画矢量线条的容器
|
||
this.initDraw("draw_" + this.$id, width, height);
|
||
this.$group = null;
|
||
if (property.haveGroup)
|
||
this.initGroup(width, height);
|
||
if (this.$editable) {
|
||
this.$workArea.on("click",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (!e) e = window.event;
|
||
if (!e.data.inthis.$editable) return;
|
||
var type = e.data.inthis.$nowType;
|
||
if (type == "cursor") {
|
||
var t = $(e.target);
|
||
var n = t.prop("tagName");
|
||
if (n == "svg" ||
|
||
(n == "DIV" && t.prop("class").indexOf("GooFlow_work") > -1) ||
|
||
n == "LABEL") e.data.inthis.blurItem();
|
||
return;
|
||
} else if (type == "direct" || type == "group") return;
|
||
var X, Y;
|
||
var ev = mousePosition(e), t = getElCoordinate(this);
|
||
X = ev.x - t.left + this.parentNode.scrollLeft - 1;
|
||
Y = ev.y - t.top + this.parentNode.scrollTop - 1;
|
||
|
||
var name = "新建节点" + e.data.inthis.$max;
|
||
var type = e.data.inthis.$nowType;
|
||
if (type == 'startround') {
|
||
name = "开始";
|
||
}
|
||
if (type == 'endround') {
|
||
name = "结束";
|
||
}
|
||
var executeadd = true;
|
||
var _nodeData = e.data.inthis.$nodeData;
|
||
$.each(_nodeData,
|
||
function(i) {
|
||
if (_nodeData[i].name == name) {
|
||
alert(name + '节点不能重复');
|
||
executeadd = false;
|
||
return false;
|
||
}
|
||
})
|
||
if (executeadd) {
|
||
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: '', });
|
||
e.data.inthis.$max++;
|
||
}
|
||
});
|
||
//划线时用的绑定
|
||
this.$workArea.mousemove({ inthis: this },
|
||
function(e) {
|
||
if (e.data.inthis.$nowType != "direct") return;
|
||
var lineStart = $(this).data("lineStart");
|
||
if (!lineStart) return;
|
||
var ev = mousePosition(e), t = getElCoordinate(this);
|
||
var X, Y;
|
||
X = ev.x - t.left + this.parentNode.scrollLeft;
|
||
Y = ev.y - t.top + this.parentNode.scrollTop;
|
||
var line = document.getElementById("GooFlow_tmp_line");
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
line.childNodes[0].setAttribute("d",
|
||
"M " + lineStart.x + " " + lineStart.y + " L " + X + " " + Y);
|
||
line.childNodes[1].setAttribute("d",
|
||
"M " + lineStart.x + " " + lineStart.y + " L " + X + " " + Y);
|
||
if (line.childNodes[1].getAttribute("marker-end") == "url(\"#arrow2\")")
|
||
line.childNodes[1].setAttribute("marker-end", "url(#arrow3)");
|
||
else line.childNodes[1].setAttribute("marker-end", "url(#arrow2)");
|
||
} else line.points.value = lineStart.x + "," + lineStart.y + " " + X + "," + Y;
|
||
});
|
||
this.$workArea.mouseup({ inthis: this },
|
||
function(e) {
|
||
if (e.data.inthis.$nowType != "direct") return;
|
||
$(this).css("cursor", "auto").removeData("lineStart");
|
||
var tmp = document.getElementById("GooFlow_tmp_line");
|
||
if (tmp) e.data.inthis.$draw.removeChild(tmp);
|
||
});
|
||
//为了结点而增加的一些集体delegate绑定
|
||
this.initWorkForNode();
|
||
//对结点进行移动或者RESIZE时用来显示的遮罩层
|
||
this.$ghost = $("<div class='rs_ghost'></div>").attr({
|
||
"unselectable": "on",
|
||
"onselectstart": 'return false',
|
||
"onselect": 'document.selection.empty()'
|
||
});
|
||
this.$bgDiv.append(this.$ghost);
|
||
this.$textArea = $("<textarea></textarea>");
|
||
this.$bgDiv.append(this.$textArea);
|
||
this.$lineMove = $("<div class='GooFlow_line_move' style='display:none'></div>"); //操作折线时的移动框
|
||
this.$workArea.append(this.$lineMove);
|
||
this.$lineMove.on("mousedown",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (e.button == 2) return false;
|
||
var lm = $(this);
|
||
lm.css({ "background-color": "#333" });
|
||
var This = e.data.inthis;
|
||
var ev = mousePosition(e), t = getElCoordinate(This.$workArea[0]);
|
||
var X, Y;
|
||
X = ev.x - t.left + This.$workArea[0].parentNode.scrollLeft;
|
||
Y = ev.y - t.top + This.$workArea[0].parentNode.scrollTop;
|
||
var p = This.$lineMove.position();
|
||
var vX = X - p.left, vY = Y - p.top;
|
||
var isMove = false;
|
||
document.onmousemove = function(e) {
|
||
if (!e) e = window.event;
|
||
var ev = mousePosition(e);
|
||
var ps = This.$lineMove.position();
|
||
X = ev.x - t.left + This.$workArea[0].parentNode.scrollLeft;
|
||
Y = ev.y - t.top + This.$workArea[0].parentNode.scrollTop;
|
||
if (This.$lineMove.data("type") == "lr") {
|
||
X = X - vX;
|
||
if (X < 0) X = 0;
|
||
else if (X > This.$workArea.width())
|
||
X = This.$workArea.width();
|
||
This.$lineMove.css({ left: X + "px" });
|
||
} else if (This.$lineMove.data("type") == "tb") {
|
||
Y = Y - vY;
|
||
if (Y < 0) Y = 0;
|
||
else if (Y > This.$workArea.height())
|
||
Y = This.$workArea.height();
|
||
This.$lineMove.css({ top: Y + "px" });
|
||
}
|
||
isMove = true;
|
||
}
|
||
document.onmouseup = function(e) {
|
||
if (isMove) {
|
||
var p = This.$lineMove.position();
|
||
if (This.$lineMove.data("type") == "lr")
|
||
This.setLineM(This.$lineMove.data("tid"), p.left + 3);
|
||
else if (This.$lineMove.data("type") == "tb")
|
||
This.setLineM(This.$lineMove.data("tid"), p.top + 3);
|
||
}
|
||
This.$lineMove.css({ "background-color": "transparent" });
|
||
if (This.$focus == This.$lineMove.data("tid")) {
|
||
This.focusItem(This.$lineMove.data("tid"));
|
||
}
|
||
document.onmousemove = null;
|
||
document.onmouseup = null;
|
||
}
|
||
});
|
||
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>"); //选定线时显示的操作框
|
||
this.$workArea.append(this.$lineOper);
|
||
this.$lineOper.on("click",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (!e) e = window.event;
|
||
if (e.target.tagName != "A" && e.target.tagName != "B") return;
|
||
var This = e.data.inthis;
|
||
var id = $(this).data("tid");
|
||
switch ($(e.target).attr("class")) {
|
||
case "b_x":
|
||
This.delLine(id);
|
||
this.style.display = "none";
|
||
break;
|
||
case "b_l1":
|
||
This.setLineType(id, "lr");
|
||
break;
|
||
case "b_l2":
|
||
This.setLineType(id, "tb");
|
||
break;
|
||
case "b_l3":
|
||
This.setLineType(id, "sl");
|
||
break;
|
||
break;
|
||
}
|
||
});
|
||
|
||
//下面绑定当结点/线/分组块的一些操作事件,这些事件可直接通过this访问对象本身
|
||
//当操作某个单元(结点/线/分组块)被添加时,触发的方法,返回FALSE可阻止添加事件的发生
|
||
//格式function(id,type,json):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值,json即addNode,addLine或addArea方法的第二个传参json.
|
||
this.onItemAdd = null;
|
||
//当操作某个单元(结点/线/分组块)被删除时,触发的方法,返回FALSE可阻止删除事件的发生
|
||
//格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值
|
||
this.onItemDel = null;
|
||
//当操作某个单元(结点/分组块)被移动时,触发的方法,返回FALSE可阻止移动事件的发生
|
||
//格式function(id,type,left,top):id是单元的唯一标识ID,type是单元的种类,有"node","area"两种取值,线line不支持移动,left是新的左边距坐标,top是新的顶边距坐标
|
||
this.onItemMove = null;
|
||
//当操作某个单元(结点/线/分组块)被重命名时,触发的方法,返回FALSE可阻止重命名事件的发生
|
||
//格式function(id,name,type):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值,name是新的名称
|
||
this.onItemRename = null;
|
||
//当操作某个单元(结点/线)被由不选中变成选中时,触发的方法,返回FALSE可阻止选中事件的发生
|
||
//格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line"两种取值,"area"不支持被选中
|
||
this.onItemFocus = null;
|
||
//当操作某个单元(结点/线)被由选中变成不选中时,触发的方法,返回FALSE可阻止取消选中事件的发生
|
||
//格式function(id,type):id是单元的唯一标识ID,type是单元的种类,有"node","line"两种取值,"area"不支持被取消选中
|
||
this.onItemBlur = null;
|
||
//当操作某个单元(结点/分组块)被重定义大小或造型时,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
|
||
//格式function(id,type,width,height):id是单元的唯一标识ID,type是单元的种类,有"node","line","area"三种取值;width是新的宽度,height是新的高度
|
||
this.onItemResize = null;
|
||
//当移动某条折线中段的位置,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
|
||
//格式function(id,M):id是单元的唯一标识ID,M是中段的新X(或Y)的坐标
|
||
this.onLineMove = null;
|
||
//当变换某条连接线的类型,触发的方法,返回FALSE可阻止重定大小/造型事件的发生
|
||
//格式function(id,type):id是单元的唯一标识ID,type是连接线的新类型,"sl":直线,"lr":中段可左右移动的折线,"tb":中段可上下移动的折线
|
||
this.onLineSetType = null;
|
||
//当用重色标注某个结点/转换线时触发的方法,返回FALSE可阻止重定大小/造型事件的发生
|
||
//格式function(id,type,mark):id是单元的唯一标识ID,type是单元类型("node"结点,"line"转换线),mark为布尔值,表示是要标注TRUE还是取消标注FALSE
|
||
this.onItemMark = null;
|
||
|
||
if (property.useOperStack && this.$editable) { //如果要使用堆栈记录操作并提供“撤销/重做”的功能,只在编辑状态下有效
|
||
this.$undoStack = [];
|
||
this.$redoStack = [];
|
||
this.$isUndo = 0;
|
||
///////////////以下是构造撤销操作/重做操作的方法
|
||
//为了节省浏览器内存空间,undo/redo中的操作缓存栈,最多只可放40步操作;超过40步时,将自动删掉最旧的一个缓存
|
||
this.pushOper = function(funcName, paras) {
|
||
var len = this.$undoStack.length;
|
||
if (this.$isUndo == 1) {
|
||
this.$redoStack.push([funcName, paras]);
|
||
this.$isUndo = false;
|
||
if (this.$redoStack.length > 40) this.$redoStack.shift();
|
||
} else {
|
||
this.$undoStack.push([funcName, paras]);
|
||
if (this.$undoStack.length > 40) this.$undoStack.shift();
|
||
if (this.$isUndo == 0) {
|
||
this.$redoStack.splice(0, this.$redoStack.length);
|
||
}
|
||
this.$isUndo = 0;
|
||
}
|
||
};
|
||
//将外部的方法加入到GooFlow对象的事务操作堆栈中,在过后的undo/redo操作中可以进行控制,一般用于对流程图以外的附加信息进行编辑的事务撤销/重做控制;
|
||
//传参func为要执行方法对象,jsonPara为外部方法仅有的一个面向字面的JSON传参,由JSON对象带入所有要传的信息;
|
||
//提示:为了让外部方法能够被UNDO/REDO,需要在编写这些外部方法实现时,加入对该方法执行后效果回退的另一个执行方法的pushExternalOper
|
||
this.pushExternalOper = function(func, jsonPara) {
|
||
this.pushOper("externalFunc", [func, jsonPara]);
|
||
};
|
||
//撤销上一步操作
|
||
this.undo = function() {
|
||
if (this.$undoStack.length == 0) return;
|
||
var tmp = this.$undoStack.pop();
|
||
this.$isUndo = 1;
|
||
if (tmp[0] == "externalFunc") {
|
||
tmp[1][0](tmp[1][1]);
|
||
} else {
|
||
//传参的数量,最多支持6个.
|
||
switch (tmp[1].length) {
|
||
case 0:
|
||
this[tmp[0]]();
|
||
break;
|
||
case 1:
|
||
this[tmp[0]](tmp[1][0]);
|
||
break;
|
||
case 2:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1]);
|
||
break;
|
||
case 3:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2]);
|
||
break;
|
||
case 4:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3]);
|
||
break;
|
||
case 5:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3], tmp[1][4]);
|
||
break;
|
||
case 6:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3], tmp[1][4], tmp[1][5]);
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
//重做最近一次被撤销的操作
|
||
this.redo = function() {
|
||
if (this.$redoStack.length == 0) return;
|
||
var tmp = this.$redoStack.pop();
|
||
this.$isUndo = 2;
|
||
if (tmp[0] == "externalFunc") {
|
||
tmp[1][0](tmp[1][1]);
|
||
} else {
|
||
//传参的数量,最多支持6个.
|
||
switch (tmp[1].length) {
|
||
case 0:
|
||
this[tmp[0]]();
|
||
break;
|
||
case 1:
|
||
this[tmp[0]](tmp[1][0]);
|
||
break;
|
||
case 2:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1]);
|
||
break;
|
||
case 3:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2]);
|
||
break;
|
||
case 4:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3]);
|
||
break;
|
||
case 5:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3], tmp[1][4]);
|
||
break;
|
||
case 6:
|
||
this[tmp[0]](tmp[1][0], tmp[1][1], tmp[1][2], tmp[1][3], tmp[1][4], tmp[1][5]);
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
}
|
||
$(document).keydown({ inthis: this },
|
||
function(e) {
|
||
//绑定键盘操作
|
||
var This = e.data.inthis;
|
||
if (This.$focus == "") return;
|
||
switch (e.keyCode) {
|
||
case 46: //删除
|
||
This.delNode(This.$focus, true);
|
||
This.delLine(This.$focus);
|
||
break;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
GooFlow.prototype = {
|
||
useSVG: "",
|
||
getSvgMarker: function(id, color) {
|
||
var m = document.createElementNS("http://www.w3.org/2000/svg", "marker");
|
||
m.setAttribute("id", id);
|
||
m.setAttribute("viewBox", "0 0 6 6");
|
||
m.setAttribute("refX", 5);
|
||
m.setAttribute("refY", 3);
|
||
m.setAttribute("markerUnits", "strokeWidth");
|
||
m.setAttribute("markerWidth", 6);
|
||
m.setAttribute("markerHeight", 6);
|
||
m.setAttribute("orient", "auto");
|
||
var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||
path.setAttribute("d", "M 0 0 L 6 3 L 0 6 z");
|
||
path.setAttribute("fill", color);
|
||
path.setAttribute("stroke-width", 0);
|
||
m.appendChild(path);
|
||
return m;
|
||
},
|
||
initDraw: function(id, width, height) {
|
||
var elem;
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
this.$draw = document.createElementNS("http://www.w3.org/2000/svg", "svg"); //可创建带有指定命名空间的元素节点
|
||
this.$workArea.prepend(this.$draw);
|
||
var defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
|
||
this.$draw.appendChild(defs);
|
||
defs.appendChild(GooFlow.prototype.getSvgMarker("arrow1", "gray"));
|
||
defs.appendChild(GooFlow.prototype.getSvgMarker("arrow2", "#ff3300"));
|
||
defs.appendChild(GooFlow.prototype.getSvgMarker("arrow3", "#ff3300"));
|
||
} else {
|
||
this.$draw = document.createElement("v:group");
|
||
this.$draw.coordsize = width * 3 + "," + height * 3;
|
||
this.$workArea.prepend("<div class='GooFlow_work_vml' style='position:relative;width:" +
|
||
width * 3 +
|
||
"px;height:" +
|
||
height * 3 +
|
||
"px'></div>");
|
||
this.$workArea.children("div")[0].insertBefore(this.$draw, null);
|
||
}
|
||
this.$draw.id = id;
|
||
this.$draw.style.width = width * 3 + "px";
|
||
this.$draw.style.height = +height * 3 + "px";
|
||
//绑定连线的点击选中以及双击编辑事件
|
||
var tmpClk = null;
|
||
if (GooFlow.prototype.useSVG != "") tmpClk = "g";
|
||
else tmpClk = "PolyLine";
|
||
if (this.$editable) {
|
||
$(this.$draw).delegate(tmpClk,
|
||
"click",
|
||
{ inthis: this },
|
||
function(e) {
|
||
e.data.inthis.focusItem(this.id, true);
|
||
});
|
||
$(this.$draw).delegate(tmpClk,
|
||
"dblclick",
|
||
{ inthis: this },
|
||
function(e) {
|
||
var This = e.data.inthis;
|
||
OpenLine(this.id, This);
|
||
//var oldTxt, x, y, from, to;
|
||
//var This = e.data.inthis;
|
||
//if (GooFlow.prototype.useSVG != "") {
|
||
// oldTxt = this.childNodes[2].textContent;
|
||
// from = this.getAttribute("from").split(",");
|
||
// to = this.getAttribute("to").split(",");
|
||
//} else {
|
||
// oldTxt = this.childNodes[1].innerHTML;
|
||
// var n = this.getAttribute("fromTo").split(",");
|
||
// from = [n[0], n[1]];
|
||
// to = [n[2], n[3]];
|
||
//}
|
||
//if (This.$lineData[this.id].type == "lr") {
|
||
// from[0] = This.$lineData[this.id].M;
|
||
// to[0] = from[0];
|
||
//}
|
||
//else if (This.$lineData[this.id].type == "tb") {
|
||
// from[1] = This.$lineData[this.id].M;
|
||
// to[1] = from[1];
|
||
//}
|
||
//x = (parseInt(from[0], 10) + parseInt(to[0], 10)) / 2 - 60;
|
||
//y = (parseInt(from[1], 10) + parseInt(to[1], 10)) / 2 - 12;
|
||
//var t = getElCoordinate(This.$workArea[0]);
|
||
//This.$textArea.val(oldTxt).css({
|
||
// display: "block", width: 120, height: 14,
|
||
// left: t.left + x - This.$workArea[0].parentNode.scrollLeft,
|
||
// top: t.top + y - This.$workArea[0].parentNode.scrollTop
|
||
//}).data("id", This.$focus).focus();
|
||
//This.$workArea.parent().one("mousedown", function (e) {
|
||
// if (e.button == 2) return false;
|
||
// This.setName(This.$textArea.data("id"), This.$textArea.val(), "line");
|
||
// This.$textArea.val("").removeData("id").hide();
|
||
//});
|
||
});
|
||
}
|
||
},
|
||
initGroup: function(width, height) {
|
||
this.$group =
|
||
$("<div class='GooFlow_work_group' style='width:" +
|
||
width * 3 +
|
||
"px;height:" +
|
||
height * 3 +
|
||
"px'></div>"); //存放背景区域的容器
|
||
this.$workArea.prepend(this.$group);
|
||
if (!this.$editable) return;
|
||
//区域划分框操作区的事件绑定
|
||
this.$group.on("mousedown",
|
||
{ inthis: this },
|
||
function(e) { //绑定RESIZE功能以及移动功能
|
||
if (e.button == 2) return false;
|
||
var This = e.data.inthis;
|
||
if (This.$nowType != "group") return;
|
||
if (This.$textArea.css("display") == "block") {
|
||
This.setName(This.$textArea.data("id"), This.$textArea.val(), "area");
|
||
This.$textArea.val("").removeData("id").hide();
|
||
return false;
|
||
};
|
||
if (!e) e = window.event;
|
||
var cursor = $(e.target).css("cursor");
|
||
var id = e.target.parentNode;
|
||
switch (cursor) {
|
||
case "nw-resize":
|
||
id = id.parentNode;
|
||
break;
|
||
case "w-resize":
|
||
id = id.parentNode;
|
||
break;
|
||
case "n-resize":
|
||
id = id.parentNode;
|
||
break;
|
||
case "move":
|
||
break;
|
||
default:
|
||
return;
|
||
}
|
||
id = id.id;
|
||
var hack = 1;
|
||
if (navigator.userAgent.indexOf("8.0") != -1) hack = 0;
|
||
var ev = mousePosition(e), t = getElCoordinate(This.$workArea[0]);
|
||
|
||
var X, Y;
|
||
X = ev.x - t.left + This.$workArea[0].parentNode.scrollLeft;
|
||
Y = ev.y - t.top + This.$workArea[0].parentNode.scrollTop;
|
||
if (cursor != "move") {
|
||
This.$ghost.css({
|
||
display: "block",
|
||
width: This.$areaData[id].width - 2 + "px",
|
||
height: This.$areaData[id].height - 2 + "px",
|
||
top: This.$areaData[id].top +
|
||
t.top -
|
||
This.$workArea[0].parentNode.scrollTop +
|
||
hack +
|
||
"px",
|
||
left: This.$areaData[id].left +
|
||
t.left -
|
||
This.$workArea[0].parentNode.scrollLeft +
|
||
hack +
|
||
"px",
|
||
cursor: cursor
|
||
});
|
||
var vX = (This.$areaData[id].left + This.$areaData[id].width) - X;
|
||
var vY = (This.$areaData[id].top + This.$areaData[id].height) - Y;
|
||
} else {
|
||
var vX = X - This.$areaData[id].left;
|
||
var vY = Y - This.$areaData[id].top;
|
||
}
|
||
var isMove = false;
|
||
This.$ghost.css("cursor", cursor);
|
||
document.onmousemove = function(e) {
|
||
if (!e) e = window.event;
|
||
var ev = mousePosition(e);
|
||
if (cursor != "move") {
|
||
X = ev.x -
|
||
t.left +
|
||
This.$workArea[0].parentNode.scrollLeft -
|
||
This.$areaData[id].left +
|
||
vX;
|
||
Y = ev.y - t.top + This.$workArea[0].parentNode.scrollTop - This.$areaData[id].top + vY;
|
||
if (X < 200) X = 200;
|
||
if (Y < 100) Y = 100;
|
||
switch (cursor) {
|
||
case "nw-resize":
|
||
This.$ghost.css({ width: X - 2 + "px", height: Y - 2 + "px" });
|
||
break;
|
||
case "w-resize":
|
||
This.$ghost.css({ width: X - 2 + "px" });
|
||
break;
|
||
case "n-resize":
|
||
This.$ghost.css({ height: Y - 2 + "px" });
|
||
break;
|
||
}
|
||
} else {
|
||
if (This.$ghost.css("display") == "none") {
|
||
This.$ghost.css({
|
||
display: "block",
|
||
width: This.$areaData[id].width - 2 + "px",
|
||
height: This.$areaData[id].height - 2 + "px",
|
||
top: This.$areaData[id].top +
|
||
t.top -
|
||
This.$workArea[0].parentNode.scrollTop +
|
||
hack +
|
||
"px",
|
||
left: This.$areaData[id].left +
|
||
t.left -
|
||
This.$workArea[0].parentNode.scrollLeft +
|
||
hack +
|
||
"px",
|
||
cursor: cursor
|
||
});
|
||
}
|
||
X = ev.x - vX;
|
||
Y = ev.y - vY;
|
||
if (X < t.left - This.$workArea[0].parentNode.scrollLeft)
|
||
X = t.left - This.$workArea[0].parentNode.scrollLeft;
|
||
else if (X + This.$workArea[0].parentNode.scrollLeft + This.$areaData[id].width >
|
||
t.left + This.$workArea.width())
|
||
X = t.left +
|
||
This.$workArea.width() -
|
||
This.$workArea[0].parentNode.scrollLeft -
|
||
This.$areaData[id].width;
|
||
if (Y < t.top - This.$workArea[0].parentNode.scrollTop)
|
||
Y = t.top - This.$workArea[0].parentNode.scrollTop;
|
||
else if (Y + This.$workArea[0].parentNode.scrollTop + This.$areaData[id].height >
|
||
t.top + This.$workArea.height())
|
||
Y = t.top +
|
||
This.$workArea.height() -
|
||
This.$workArea[0].parentNode.scrollTop -
|
||
This.$areaData[id].height;
|
||
This.$ghost.css({ left: X + hack + "px", top: Y + hack + "px" });
|
||
}
|
||
isMove = true;
|
||
}
|
||
document.onmouseup = function(e) {
|
||
This.$ghost.empty().hide();
|
||
document.onmousemove = null;
|
||
document.onmouseup = null;
|
||
if (!isMove) return;
|
||
if (cursor != "move")
|
||
This.resizeArea(id, This.$ghost.outerWidth(), This.$ghost.outerHeight());
|
||
else
|
||
This.moveArea(id,
|
||
X + This.$workArea[0].parentNode.scrollLeft - t.left,
|
||
Y + This.$workArea[0].parentNode.scrollTop - t.top);
|
||
return false;
|
||
}
|
||
});
|
||
//绑定修改文字说明功能
|
||
this.$group.on("dblclick",
|
||
{ inthis: this },
|
||
function(e) {
|
||
var This = e.data.inthis;
|
||
if (This.$nowType != "group") return;
|
||
if (!e) e = window.event;
|
||
if (e.target.tagName != "LABEL") return false;
|
||
var oldTxt = e.target.innerHTML;
|
||
var p = e.target.parentNode;
|
||
var x = parseInt(p.style.left, 10) + 18, y = parseInt(p.style.top, 10) + 1;
|
||
var t = getElCoordinate(This.$workArea[0]);
|
||
This.$textArea.val(oldTxt).css({
|
||
display: "block",
|
||
width: 100,
|
||
height: 14,
|
||
left: t.left + x - This.$workArea[0].parentNode.scrollLeft,
|
||
top: t.top + y - This.$workArea[0].parentNode.scrollTop
|
||
}).data("id", p.id).focus();
|
||
This.$workArea.parent().one("mousedown",
|
||
function(e) {
|
||
if (e.button == 2) return false;
|
||
if (This.$textArea.css("display") == "block") {
|
||
This.setName(This.$textArea.data("id"), This.$textArea.val(), "area");
|
||
This.$textArea.val("").removeData("id").hide();
|
||
}
|
||
});
|
||
return false;
|
||
});
|
||
//绑定点击事件
|
||
this.$group.mouseup({ inthis: this },
|
||
function(e) {
|
||
|
||
var This = e.data.inthis;
|
||
if (This.$nowType != "group") return;
|
||
if (!e) e = window.event;
|
||
switch ($(e.target).attr("class")) {
|
||
case "rs_close":
|
||
This.delArea(e.target.parentNode.parentNode.id);
|
||
return false; //删除该分组区域
|
||
case "bg":
|
||
return;
|
||
}
|
||
switch (e.target.tagName) {
|
||
case "LABEL":
|
||
return false;
|
||
case "B": //绑定变色功能
|
||
var id = e.target.parentNode.id;
|
||
switch (This.$areaData[id].color) {
|
||
case "red":
|
||
This.setAreaColor(id, "yellow");
|
||
break;
|
||
case "yellow":
|
||
This.setAreaColor(id, "blue");
|
||
break;
|
||
case "blue":
|
||
This.setAreaColor(id, "green");
|
||
break;
|
||
case "green":
|
||
This.setAreaColor(id, "red");
|
||
break;
|
||
}
|
||
return false;
|
||
}
|
||
if (e.data.inthis.$ghost.css("display") == "none") {
|
||
var X, Y;
|
||
var ev = mousePosition(e), t = getElCoordinate(this);
|
||
X = ev.x - t.left + this.parentNode.parentNode.scrollLeft - 1;
|
||
Y = ev.y - t.top + this.parentNode.parentNode.scrollTop - 1;
|
||
var color = ["red", "yellow", "blue", "green"];
|
||
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
|
||
});
|
||
e.data.inthis.$max++;
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
//每一种类型结点及其按钮的说明文字
|
||
setNodeRemarks: function(remark) {
|
||
if (this.$tool != null) {
|
||
this.$tool.children("a").each(function() {
|
||
this.title = remark[$(this).attr("id").split("btn_")[1]];
|
||
});
|
||
this.$nodeRemark = remark;
|
||
}
|
||
},
|
||
|
||
//切换左边工具栏按钮,传参TYPE表示切换成哪种类型的按钮
|
||
switchToolBtn: function(type) {
|
||
this.$tool.children("#" + this.$id + "_btn_" + this.$nowType.split(" ")[0])
|
||
.attr("class", "GooFlow_tool_btn");
|
||
if (this.$nowType == "group") {
|
||
this.$workArea.prepend(this.$group);
|
||
for (var key in this.$areaDom)
|
||
this.$areaDom[key].addClass("lock").children("div:eq(1)").css("display", "none");
|
||
}
|
||
this.$nowType = type;
|
||
this.$tool.children("#" + this.$id + "_btn_" + type.split(" ")[0])
|
||
.attr("class", "GooFlow_tool_btndown");
|
||
if (this.$nowType == "group") {
|
||
this.blurItem();
|
||
this.$workArea.append(this.$group);
|
||
for (var key in this.$areaDom)
|
||
this.$areaDom[key].removeClass("lock").children("div:eq(1)").css("display", "");
|
||
}
|
||
if (this.$textArea.css("display") == "none") this.$textArea.removeData("id").val("").hide();
|
||
},
|
||
//增加一个流程结点,传参为一个JSON,有id,name,top,left,width,height,type(结点类型)等属性
|
||
addNode: function(id, json) {
|
||
if (this.onItemAdd != null && !this.onItemAdd(id, "node", json)) return;
|
||
if (this.$undoStack && this.$editable) {
|
||
this.pushOper("delNode", [id]);
|
||
}
|
||
var mark = json.type;
|
||
if (json.type != "startround" && json.type != "endround") {
|
||
if (!json.width || json.width < 86) json.width = 150;
|
||
if (!json.height || json.height < 24) json.height = 65;
|
||
if (!json.top || json.top < 0) json.top = 0;
|
||
if (!json.left || json.left < 0) json.left = 0;
|
||
var hack = 0;
|
||
if (navigator.userAgent.indexOf("8.0") != -1) hack = 2;
|
||
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>");
|
||
if (json.type.indexOf(" mix") > -1) this.$nodeDom[id].addClass(mark);
|
||
//json.css = mark;
|
||
//json.img = mark;
|
||
} else {
|
||
json.width = 24;
|
||
json.height = 24;
|
||
var name = json.name;
|
||
if (json.type == 'startround') {
|
||
name = "开始";
|
||
}
|
||
if (json.type == 'endround') {
|
||
name = "结束";
|
||
}
|
||
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>");
|
||
}
|
||
var ua = navigator.userAgent.toLowerCase();
|
||
if (ua.indexOf('msie') != -1 && ua.indexOf('8.0') != -1)
|
||
this.$nodeDom[id].css("filter",
|
||
"progid:DXImageTransform.Microsoft.Shadow(color=#94AAC2,direction=135,strength=2)");
|
||
this.$workArea.append(this.$nodeDom[id]);
|
||
this.$nodeData[id] = json;
|
||
++this.$nodeCount;
|
||
if (this.$editable) {
|
||
this.$nodeData[id].alt = true;
|
||
if (this.$deletedItem[id]) delete this.$deletedItem[id]; //在回退删除操作时,去掉该元素的删除记录
|
||
}
|
||
},
|
||
initWorkForNode: function() {
|
||
//绑定点击事件
|
||
this.$workArea.delegate(".GooFlow_item",
|
||
"click",
|
||
{ inthis: this },
|
||
function(e) {
|
||
e.data.inthis.focusItem(this.id, true);
|
||
$(this).removeClass("item_mark");
|
||
//if (!$(this).hasClass("item_startround")) {
|
||
// LoadrightMenu("#" + this.id);
|
||
//}
|
||
//if (!$(this).hasClass("item_endround")) {
|
||
// LoadrightMenu("#" + this.id);
|
||
//}
|
||
});
|
||
//绑定右击事件
|
||
this.$workArea.delegate(".GooFlow_item",
|
||
"contextmenu",
|
||
{ inthis: this },
|
||
function(e) {
|
||
e.data.inthis.focusItem(this.id, true);
|
||
$(this).removeClass("item_mark");
|
||
return false;
|
||
});
|
||
//绑定用鼠标移动事件
|
||
this.$workArea.delegate(".ico",
|
||
"mousedown",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (!e) e = window.event;
|
||
if (e.button == 2) return false;
|
||
var This = e.data.inthis;
|
||
if (This.$nowType == "direct") return;
|
||
var Dom = $(this).parents(".GooFlow_item");
|
||
var id = Dom.attr("id");
|
||
This.focusItem(id, true);
|
||
var hack = 1;
|
||
if (navigator.userAgent.indexOf("8.0") != -1) hack = 0;
|
||
var ev = mousePosition(e), t = getElCoordinate(This.$workArea[0]);
|
||
|
||
Dom.children("table").clone().prependTo(This.$ghost);
|
||
var X, Y;
|
||
X = ev.x - t.left + This.$workArea[0].parentNode.scrollLeft;
|
||
Y = ev.y - t.top + This.$workArea[0].parentNode.scrollTop;
|
||
var vX = X - This.$nodeData[id].left, vY = Y - This.$nodeData[id].top;
|
||
var isMove = false;
|
||
document.onmousemove = function(e) {
|
||
if (!e) e = window.event;
|
||
var ev = mousePosition(e);
|
||
if (X == ev.x - vX && Y == ev.y - vY) return false;
|
||
X = ev.x - vX;
|
||
Y = ev.y - vY;
|
||
|
||
if (isMove && This.$ghost.css("display") == "none") {
|
||
This.$ghost.css({
|
||
display: "block",
|
||
width: $('#' + id).width() - 2 + "px",
|
||
height: $('#' + id).height() - 2 + "px",
|
||
top: This.$nodeData[id].top +
|
||
t.top -
|
||
This.$workArea[0].parentNode.scrollTop +
|
||
hack +
|
||
"px",
|
||
left: This.$nodeData[id].left +
|
||
t.left -
|
||
This.$workArea[0].parentNode.scrollLeft +
|
||
hack +
|
||
"px",
|
||
cursor: "move"
|
||
});
|
||
}
|
||
|
||
if (X < t.left - This.$workArea[0].parentNode.scrollLeft)
|
||
X = t.left - This.$workArea[0].parentNode.scrollLeft;
|
||
else if (X + This.$workArea[0].parentNode.scrollLeft + This.$nodeData[id].width >
|
||
t.left + This.$workArea.width())
|
||
X = t.left +
|
||
This.$workArea.width() -
|
||
This.$workArea[0].parentNode.scrollLeft -
|
||
This.$nodeData[id].width;
|
||
if (Y < t.top - This.$workArea[0].parentNode.scrollTop)
|
||
Y = t.top - This.$workArea[0].parentNode.scrollTop;
|
||
else if (Y + This.$workArea[0].parentNode.scrollTop + This.$nodeData[id].height >
|
||
t.top + This.$workArea.height())
|
||
Y = t.top +
|
||
This.$workArea.height() -
|
||
This.$workArea[0].parentNode.scrollTop -
|
||
This.$nodeData[id].height;
|
||
This.$ghost.css({ left: X + hack + "px", top: Y + hack + "px" });
|
||
isMove = true;
|
||
}
|
||
document.onmouseup = function(e) {
|
||
if (isMove)
|
||
This.moveNode(id,
|
||
X + This.$workArea[0].parentNode.scrollLeft - t.left,
|
||
Y + This.$workArea[0].parentNode.scrollTop - t.top);
|
||
This.$ghost.empty().hide();
|
||
document.onmousemove = null;
|
||
document.onmouseup = null;
|
||
}
|
||
});
|
||
if (!this.$editable) return;
|
||
//绑定鼠标覆盖/移出事件
|
||
this.$workArea.delegate(".GooFlow_item",
|
||
"mouseenter",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (e.data.inthis.$nowType != "direct") return;
|
||
$(this).addClass("item_mark");
|
||
});
|
||
this.$workArea.delegate(".GooFlow_item",
|
||
"mouseleave",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (e.data.inthis.$nowType != "direct") return;
|
||
$(this).removeClass("item_mark");
|
||
});
|
||
//绑定连线时确定初始点
|
||
this.$workArea.delegate(".GooFlow_item",
|
||
"mousedown",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (e.button == 2) return false;
|
||
var This = e.data.inthis;
|
||
if (This.$nowType != "direct") return;
|
||
var ev = mousePosition(e), t = getElCoordinate(This.$workArea[0]);
|
||
var X, Y;
|
||
X = ev.x - t.left + This.$workArea[0].parentNode.scrollLeft;
|
||
Y = ev.y - t.top + This.$workArea[0].parentNode.scrollTop;
|
||
This.$workArea.data("lineStart", { "x": X, "y": Y, "id": this.id }).css("cursor", "crosshair");
|
||
var line = GooFlow.prototype.drawLine("GooFlow_tmp_line", [X, Y], [X, Y], true, true);
|
||
This.$draw.appendChild(line);
|
||
});
|
||
//绑定连线时确定结束点
|
||
this.$workArea.delegate(".GooFlow_item",
|
||
"mouseup",
|
||
{ inthis: this },
|
||
function(e) {
|
||
var This = e.data.inthis;
|
||
if (This.$nowType != "direct") return;
|
||
var lineStart = This.$workArea.data("lineStart");
|
||
if (lineStart)
|
||
This.addLine(This.$id + "_line_" + This.$max,
|
||
{ from: lineStart.id, to: this.id, name: "" });
|
||
This.$max++;
|
||
});
|
||
//绑定双击编辑事件
|
||
this.$workArea.delegate(".GooFlow_item > .span",
|
||
"dblclick",
|
||
{ inthis: this },
|
||
function(e) {
|
||
var This = e.data.inthis;
|
||
var type = $('.item_focus').hasClass('item_startround');
|
||
if (type) {
|
||
OpenNode(This);
|
||
}
|
||
//var oldTxt = this.innerHTML;
|
||
//var This = e.data.inthis;
|
||
//var id = this.parentNode.id;
|
||
//var t = getElCoordinate(This.$workArea[0]);
|
||
//This.$textArea.val(oldTxt).css({
|
||
// display: "block", height: $(this).height(), width: 100,
|
||
// left: t.left + This.$nodeData[id].left - This.$workArea[0].parentNode.scrollLeft - 24,
|
||
// top: t.top + This.$nodeData[id].top - This.$workArea[0].parentNode.scrollTop + 26
|
||
//})
|
||
// .data("id", This.$focus).focus();
|
||
//This.$workArea.parent().one("mousedown", function (e) {
|
||
// if (e.button == 2) return false;
|
||
// This.setName(This.$textArea.data("id"), This.$textArea.val(), "node");
|
||
// This.$textArea.val("").removeData("id").hide();
|
||
//});
|
||
});
|
||
//节点双击事件
|
||
this.$workArea.delegate(".ico + td",
|
||
"dblclick",
|
||
{ inthis: this },
|
||
function(e) {
|
||
var This = e.data.inthis;
|
||
OpenNode(This);
|
||
//var oldTxt = this.innerHTML;
|
||
//var This = e.data.inthis;
|
||
//var id = $(this).parents(".GooFlow_item").attr("id");
|
||
//var t = getElCoordinate(This.$workArea[0]);
|
||
//This.$textArea.val(oldTxt).css({
|
||
// display: "block", width: $(this).width() + 24, height: $(this).height(),
|
||
// left: t.left + 24 + This.$nodeData[id].left - This.$workArea[0].parentNode.scrollLeft,
|
||
// top: t.top + 2 + This.$nodeData[id].top - This.$workArea[0].parentNode.scrollTop
|
||
//})
|
||
// .data("id", This.$focus).focus();
|
||
//This.$workArea.parent().one("mousedown", function (e) {
|
||
// if (e.button == 2) return false;
|
||
// This.setName(This.$textArea.data("id"), This.$textArea.val(), "node");
|
||
// This.$textArea.val("").removeData("id").hide();
|
||
//});
|
||
});
|
||
//绑定结点的删除功能
|
||
this.$workArea.delegate(".rs_close",
|
||
"click",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (!e) e = window.event;
|
||
e.data.inthis.delNode(e.data.inthis.$focus);
|
||
return false;
|
||
});
|
||
//绑定结点的RESIZE功能
|
||
this.$workArea.delegate(".GooFlow_item > div > div[class!=rs_close]",
|
||
"mousedown",
|
||
{ inthis: this },
|
||
function(e) {
|
||
if (!e) e = window.event;
|
||
if (e.button == 2) return false;
|
||
var cursor = $(this).css("cursor");
|
||
if (cursor == "pointer") {
|
||
return;
|
||
}
|
||
var This = e.data.inthis;
|
||
var id = This.$focus;
|
||
This.switchToolBtn("cursor");
|
||
e.cancelBubble = true;
|
||
e.stopPropagation();
|
||
var hack = 1;
|
||
if (navigator.userAgent.indexOf("8.0") != -1) hack = 0;
|
||
var ev = mousePosition(e), t = getElCoordinate(This.$workArea[0]);
|
||
This.$ghost.css({
|
||
display: "block",
|
||
width: This.$nodeData[id].width - 2 + "px",
|
||
height: This.$nodeData[id].height - 2 + "px",
|
||
top: This.$nodeData[id].top + t.top - This.$workArea[0].parentNode.scrollTop + hack + "px",
|
||
left: This.$nodeData[id].left +
|
||
t.left -
|
||
This.$workArea[0].parentNode.scrollLeft +
|
||
hack +
|
||
"px",
|
||
cursor: cursor
|
||
});
|
||
var X, Y;
|
||
X = ev.x - t.left + This.$workArea[0].parentNode.scrollLeft;
|
||
Y = ev.y - t.top + This.$workArea[0].parentNode.scrollTop;
|
||
var vX = (This.$nodeData[id].left + This.$nodeData[id].width) - X;
|
||
var vY = (This.$nodeData[id].top + This.$nodeData[id].height) - Y;
|
||
var isMove = false;
|
||
This.$ghost.css("cursor", cursor);
|
||
document.onmousemove = function(e) {
|
||
if (!e) e = window.event;
|
||
var ev = mousePosition(e);
|
||
X = ev.x - t.left + This.$workArea[0].parentNode.scrollLeft - This.$nodeData[id].left + vX;
|
||
Y = ev.y - t.top + This.$workArea[0].parentNode.scrollTop - This.$nodeData[id].top + vY;
|
||
if (X < 86) X = 86;
|
||
if (Y < 24) Y = 24;
|
||
isMove = true;
|
||
switch (cursor) {
|
||
case "nw-resize":
|
||
This.$ghost.css({ width: X - 2 + "px", height: Y - 2 + "px" });
|
||
break;
|
||
case "w-resize":
|
||
This.$ghost.css({ width: X - 2 + "px" });
|
||
break;
|
||
case "n-resize":
|
||
This.$ghost.css({ height: Y - 2 + "px" });
|
||
break;
|
||
}
|
||
}
|
||
document.onmouseup = function(e) {
|
||
This.$ghost.hide();
|
||
if (!isMove) return;
|
||
if (!e) e = window.event;
|
||
This.resizeNode(id, This.$ghost.outerWidth(), This.$ghost.outerHeight());
|
||
document.onmousemove = null;
|
||
document.onmouseup = null;
|
||
}
|
||
});
|
||
},
|
||
//获取结点/连线/分组区域的详细信息
|
||
getItemInfo: function(id, type) {
|
||
switch (type) {
|
||
case "node":
|
||
return this.$nodeData[id] || null;
|
||
case "line":
|
||
return this.$lineData[id] || null;
|
||
case "area":
|
||
return this.$areaData[id] || null;
|
||
}
|
||
},
|
||
//取消所有结点/连线被选定的状态
|
||
blurItem: function() {
|
||
if (this.$focus != "") {
|
||
var jq = $("#" + this.$focus);
|
||
if (jq.prop("tagName") == "DIV") {
|
||
if (this.onItemBlur != null && !this.onItemBlur(id, "node")) return false;
|
||
jq.removeClass("item_focus").children("div:eq(0)").css("display", "none");
|
||
} else {
|
||
if (this.onItemBlur != null && !this.onItemBlur(id, "line")) return false;
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
if (!this.$lineData[this.$focus].marked) {
|
||
jq[0].childNodes[1].setAttribute("stroke", "gray");
|
||
jq[0].childNodes[1].setAttribute("marker-end", "url(#arrow1)");
|
||
}
|
||
} else {
|
||
if (!this.$lineData[this.$focus].marked) jq[0].strokeColor = "gray";
|
||
}
|
||
this.$lineMove.hide().removeData("type").removeData("tid");
|
||
if (this.$editable) this.$lineOper.hide().removeData("tid");
|
||
}
|
||
}
|
||
this.$focus = "";
|
||
return true;
|
||
},
|
||
//选定某个结点/转换线 bool:TRUE决定了要触发选中事件,FALSE则不触发选中事件,多用在程序内部调用。
|
||
focusItem: function(id, bool) {
|
||
var jq = $("#" + id);
|
||
if (jq.length == 0) return;
|
||
if (!this.blurItem()) return; //先执行"取消选中",如果返回FLASE,则也会阻止选定事件继续进行.
|
||
if (jq.prop("tagName") == "DIV") {
|
||
if (bool && this.onItemFocus != null && !this.onItemFocus(id, "node")) return;
|
||
jq.addClass("item_focus");
|
||
if (this.$editable) jq.children("div:eq(0)").css("display", "block");
|
||
this.$workArea.append(jq);
|
||
} else { //如果是连接线
|
||
if (this.onItemFocus != null && !this.onItemFocus(id, "line")) return;
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
jq[0].childNodes[1].setAttribute("stroke", "#ff3300");
|
||
jq[0].childNodes[1].setAttribute("marker-end", "url(#arrow2)");
|
||
} else jq[0].strokeColor = "#ff3300";
|
||
if (!this.$editable) return;
|
||
var x, y, from, to;
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
from = jq.attr("from").split(",");
|
||
to = jq.attr("to").split(",");
|
||
} else {
|
||
var n = jq[0].getAttribute("fromTo").split(",");
|
||
from = [n[0], n[1]];
|
||
to = [n[2], n[3]];
|
||
}
|
||
from[0] = parseInt(from[0], 10);
|
||
from[1] = parseInt(from[1], 10);
|
||
to[0] = parseInt(to[0], 10);
|
||
to[1] = parseInt(to[1], 10);
|
||
//var t=getElCoordinate(this.$workArea[0]);
|
||
if (this.$lineData[id].type == "lr") {
|
||
from[0] = this.$lineData[id].M;
|
||
to[0] = from[0];
|
||
|
||
this.$lineMove.css({
|
||
width: "5px",
|
||
height: (to[1] - from[1]) * (to[1] > from[1] ? 1 : -1) + "px",
|
||
left: from[0] - 3 + "px",
|
||
top: (to[1] > from[1] ? from[1] : to[1]) + 1 + "px",
|
||
cursor: "e-resize",
|
||
display: "block"
|
||
}).data({ "type": "lr", "tid": id });
|
||
} else if (this.$lineData[id].type == "tb") {
|
||
from[1] = this.$lineData[id].M;
|
||
to[1] = from[1];
|
||
this.$lineMove.css({
|
||
width: (to[0] - from[0]) * (to[0] > from[0] ? 1 : -1) + "px",
|
||
height: "5px",
|
||
left: (to[0] > from[0] ? from[0] : to[0]) + 1 + "px",
|
||
top: from[1] - 3 + "px",
|
||
cursor: "s-resize",
|
||
display: "block"
|
||
}).data({ "type": "tb", "tid": id });
|
||
}
|
||
x = (from[0] + to[0]) / 2 - 35;
|
||
y = (from[1] + to[1]) / 2 + 6;
|
||
this.$lineOper.css({ display: "block", left: x + "px", top: y + "px" }).data("tid", id);
|
||
}
|
||
this.$focus = id;
|
||
this.switchToolBtn("cursor");
|
||
},
|
||
//移动结点到一个新的位置
|
||
moveNode: function(id, left, top) {
|
||
if (!this.$nodeData[id]) return;
|
||
if (this.onItemMove != null && !this.onItemMove(id, "node", left, top)) return;
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$nodeData[id].left, this.$nodeData[id].top];
|
||
this.pushOper("moveNode", paras);
|
||
}
|
||
if (left < 0) left = 0;
|
||
if (top < 0) top = 0;
|
||
$("#" + id).css({ left: left + "px", top: top + "px" });
|
||
this.$nodeData[id].left = left;
|
||
this.$nodeData[id].top = top;
|
||
//重画转换线
|
||
this.resetLines(id, this.$nodeData[id]);
|
||
if (this.$editable) {
|
||
this.$nodeData[id].alt = true;
|
||
}
|
||
},
|
||
//设置结点/连线/分组区域的文字信息
|
||
setName: function(id, name, type, setinfo) {
|
||
var oldName;
|
||
if (type == "node") { //如果是结点
|
||
this.$nodeData[id].setInfo = setinfo;
|
||
if (!this.$nodeData[id])
|
||
if (this.$nodeData[id].name == name)
|
||
if (this.onItemRename != null && !this.onItemRename(id, name, "node"))
|
||
oldName = this.$nodeData[id].name;
|
||
this.$nodeData[id].name = name;
|
||
if (this.$nodeData[id].type.indexOf("round") > 1) {
|
||
this.$nodeDom[id].children(".span").text(name);
|
||
} else {
|
||
this.$nodeDom[id].find("td:eq(1)").text(name);
|
||
var hack = 0;
|
||
if (navigator.userAgent.indexOf("8.0") != -1) hack = 2;
|
||
var width = this.$nodeDom[id].outerWidth();
|
||
var height = this.$nodeDom[id].outerHeight();
|
||
this.$nodeDom[id].children("table").css({ width: width - 2 + "px", height: height - 2 + "px" });
|
||
this.$nodeData[id].width = width;
|
||
this.$nodeData[id].height = height;
|
||
}
|
||
if (this.$editable) {
|
||
this.$nodeData[id].alt = true;
|
||
}
|
||
//重画转换线
|
||
this.resetLines(id, this.$nodeData[id]);
|
||
} else if (type == "line") { //如果是线
|
||
this.$lineData[id].setInfo = setinfo;
|
||
if (!this.$lineData[id])
|
||
if (this.$lineData[id].name == name)
|
||
if (this.onItemRename != null && !this.onItemRename(id, name, "line"))
|
||
oldName = this.$lineData[id].name;
|
||
this.$lineData[id].name = name;
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
this.$lineDom[id].childNodes[2].textContent = name;
|
||
} else {
|
||
this.$lineDom[id].childNodes[1].innerHTML = name;
|
||
var n = this.$lineDom[id].getAttribute("fromTo").split(",");
|
||
var x;
|
||
if (this.$lineData[id].type != "lr") {
|
||
x = (n[2] - n[0]) / 2;
|
||
} else {
|
||
var Min = n[2] > n[0] ? n[0] : n[2];
|
||
if (Min > this.$lineData[id].M) Min = this.$lineData[id].M;
|
||
x = this.$lineData[id].M - Min;
|
||
}
|
||
if (x < 0) x = x * -1;
|
||
this.$lineDom[id].childNodes[1].style.left =
|
||
x - this.$lineDom[id].childNodes[1].offsetWidth / 2 + 4 + "px";
|
||
}
|
||
if (this.$editable) {
|
||
this.$lineData[id].alt = true;
|
||
}
|
||
} else if (type == "area") { //如果是分组区域
|
||
if (!this.$areaData[id]) return;
|
||
if (this.$areaData[id].name == name) return;
|
||
if (this.onItemRename != null && !this.onItemRename(id, name, "area")) return;
|
||
oldName = this.$areaData[id].name;
|
||
this.$areaData[id].name = name;
|
||
this.$areaDom[id].children("label").text(name);
|
||
if (this.$editable) {
|
||
this.$areaData[id].alt = true;
|
||
}
|
||
}
|
||
if (this.$undoStack) {
|
||
var paras = [id, oldName, type];
|
||
this.pushOper("setName", paras);
|
||
}
|
||
},
|
||
//设置结点的尺寸,仅支持非开始/结束结点
|
||
resizeNode: function(id, width, height) {
|
||
if (!this.$nodeData[id]) return;
|
||
if (this.onItemResize != null && !this.onItemResize(id, "node", width, height)) return;
|
||
if (this.$nodeData[id].type == "start" || this.$nodeData[id].type == "end") return;
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$nodeData[id].width, this.$nodeData[id].height];
|
||
this.pushOper("resizeNode", paras);
|
||
}
|
||
var hack = 0;
|
||
if (navigator.userAgent.indexOf("8.0") != -1) hack = 2;
|
||
this.$nodeDom[id].children("table").css({ width: width - 2 + "px", height: height - 2 + "px" });
|
||
width = this.$nodeDom[id].outerWidth() - hack;
|
||
height = this.$nodeDom[id].outerHeight() - hack;
|
||
this.$nodeDom[id].children("table").css({ width: width - 2 + "px", height: height - 2 + "px" });
|
||
this.$nodeData[id].width = width;
|
||
this.$nodeData[id].height = height;
|
||
if (this.$editable) {
|
||
this.$nodeData[id].alt = true;
|
||
}
|
||
//重画转换线
|
||
this.resetLines(id, this.$nodeData[id]);
|
||
},
|
||
//删除结点
|
||
delNode: function(id) {
|
||
if (!this.$nodeData[id]) return;
|
||
if (this.onItemDel != null && !this.onItemDel(id, "node")) return;
|
||
//先删除可能的连线
|
||
for (var k in this.$lineData) {
|
||
if (this.$lineData[k].from == id || this.$lineData[k].to == id) {
|
||
//this.$draw.removeChild(this.$lineDom[k]);
|
||
//delete this.$lineData[k];
|
||
//delete this.$lineDom[k];
|
||
this.delLine(k);
|
||
}
|
||
}
|
||
//再删除结点本身
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$nodeData[id]];
|
||
this.pushOper("addNode", paras);
|
||
}
|
||
delete this.$nodeData[id];
|
||
this.$nodeDom[id].remove();
|
||
delete this.$nodeDom[id];
|
||
--this.$nodeCount;
|
||
if (this.$focus == id) this.$focus = "";
|
||
|
||
if (this.$editable) {
|
||
//在回退新增操作时,如果节点ID以this.$id+"_node_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
|
||
if (id.indexOf(this.$id + "_node_") < 0)
|
||
this.$deletedItem[id] = "node";
|
||
}
|
||
},
|
||
//设置流程图的名称
|
||
setTitle: function(text) {
|
||
this.$title = text;
|
||
if (this.$head) this.$head.children("label").attr("title", text).text(text);
|
||
},
|
||
//载入一组数据
|
||
loadData: function(data) {
|
||
if (data == undefined) {
|
||
data = "";
|
||
}
|
||
var t = this.$editable;
|
||
this.$editable = false;
|
||
if (data.title) this.setTitle(data.title);
|
||
if (data.initNum) this.$max = data.initNum;
|
||
for (var i in data.nodes)
|
||
this.addNode(data.nodes[i].id, data.nodes[i]);
|
||
for (var j in data.lines)
|
||
this.addLine(data.lines[j].id, data.lines[j]);
|
||
for (var k in data.areas)
|
||
this.addArea(data.areas[k].id, data.areas[k]);
|
||
this.$editable = t;
|
||
this.$deletedItem = {};
|
||
},
|
||
//用AJAX方式,远程读取一组数据
|
||
//参数para为JSON结构,与JQUERY中$.ajax()方法的传参一样
|
||
loadDataAjax: function(para) {
|
||
var This = this;
|
||
$.ajax({
|
||
type: para.type,
|
||
url: para.url,
|
||
dataType: "json",
|
||
data: para.data,
|
||
success: function(msg) {
|
||
if (para.dataFilter) para.dataFilter(msg, "json");
|
||
This.loadData(msg);
|
||
if (para.success) para.success(msg);
|
||
},
|
||
error: function(XMLHttpRequest, textStatus, errorThrown) {
|
||
if (para.error) para.error(textStatus, errorThrown);
|
||
}
|
||
})
|
||
},
|
||
//把画好的整个流程图导出到一个变量中(其实也可以直接访问GooFlow对象的$nodeData,$lineData,$areaData这三个JSON属性)
|
||
exportData: function() {
|
||
var ret = {
|
||
title: this.$title,
|
||
nodes: this.$nodeData,
|
||
lines: this.$lineData,
|
||
areas: this.$areaData,
|
||
initNum: this.$max
|
||
};
|
||
|
||
var _nodeobject = [], _lineobject = [];
|
||
for (var k1 in ret.nodes) {
|
||
if (!ret.nodes[k1].marked) {
|
||
delete ret.nodes[k1]["marked"];
|
||
}
|
||
ret.nodes[k1]["id"] = k1;
|
||
_nodeobject.push(ret.nodes[k1]);
|
||
}
|
||
ret.nodes = _nodeobject;
|
||
for (var k2 in ret.lines) {
|
||
if (!ret.lines[k2].marked) {
|
||
delete ret.lines[k2]["marked"];
|
||
}
|
||
ret.lines[k2]["id"] = k2;
|
||
_lineobject.push(ret.lines[k2]);
|
||
}
|
||
ret.lines = _lineobject;
|
||
return ret;
|
||
},
|
||
//只把本次编辑流程图中作了变更(包括增删改)的元素导出到一个变量中,以方便用户每次编辑载入的流程图后只获取变更过的数据
|
||
exportAlter: function() {
|
||
var ret = { nodes: {}, lines: {}, areas: {} };
|
||
for (var k1 in this.$nodeData) {
|
||
if (this.$nodeData[k1].alt) {
|
||
ret.nodes[k1] = this.$nodeData[k1];
|
||
}
|
||
}
|
||
for (var k2 in this.$lineData) {
|
||
if (this.$lineData[k2].alt) {
|
||
ret.lines[k2] = this.$lineData[k2];
|
||
}
|
||
}
|
||
for (var k3 in this.$areaData) {
|
||
if (this.$areaData[k3].alt) {
|
||
ret.areas[k3] = this.$areaData[k3];
|
||
}
|
||
}
|
||
ret.deletedItem = this.$deletedItem;
|
||
return ret;
|
||
},
|
||
//变更元素的ID,一般用于快速保存后,将后台返回新元素的ID更新到页面中;type为元素类型(节点,连线,区块)
|
||
transNewId: function(oldId, newId, type) {
|
||
var tmp;
|
||
switch (type) {
|
||
case "node":
|
||
if (this.$nodeData[oldId]) {
|
||
tmp = this.$nodeData[oldId];
|
||
delete this.$nodeData[oldId];
|
||
this.$nodeData[newId] = tmp;
|
||
}
|
||
break;
|
||
case "line":
|
||
if (this.$lineData[oldId]) {
|
||
tmp = this.$lineData[oldId];
|
||
delete this.$lineData[oldId];
|
||
this.$lineData[newId] = tmp;
|
||
}
|
||
break;
|
||
case "area":
|
||
if (this.$areaData[oldId]) {
|
||
tmp = this.$areaData[oldId];
|
||
delete this.$areaData[oldId];
|
||
this.$areaData[newId] = tmp;
|
||
}
|
||
break;
|
||
}
|
||
},
|
||
//清空工作区及已载入的数据
|
||
clearData: function() {
|
||
for (var key in this.$nodeData) {
|
||
this.delNode(key);
|
||
}
|
||
for (var key in this.$lineData) {
|
||
this.delLine(key);
|
||
}
|
||
for (var key in this.$areaData) {
|
||
this.delArea(key);
|
||
}
|
||
this.$deletedItem = {};
|
||
},
|
||
//销毁自己
|
||
destrory: function() {
|
||
this.$bgDiv.empty();
|
||
this.$lineData = null;
|
||
this.$nodeData = null;
|
||
this.$lineDom = null;
|
||
this.$nodeDom = null;
|
||
this.$areaDom = null;
|
||
this.$areaData = null;
|
||
this.$nodeCount = 0;
|
||
this.$areaCount = 0;
|
||
this.$areaCount = 0;
|
||
this.$deletedItem = {};
|
||
},
|
||
///////////以下为有关画线的方法
|
||
//绘制一条箭头线,并返回线的DOM
|
||
drawLine: function(id, sp, ep, mark, dash) {
|
||
var line;
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
line = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
||
var hi = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||
var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||
|
||
if (id != "") line.setAttribute("id", id);
|
||
line.setAttribute("from", sp[0] + "," + sp[1]);
|
||
line.setAttribute("to", ep[0] + "," + ep[1]);
|
||
hi.setAttribute("visibility", "hidden");
|
||
hi.setAttribute("stroke-width", 9);
|
||
hi.setAttribute("fill", "none");
|
||
hi.setAttribute("stroke", "white");
|
||
hi.setAttribute("d", "M " + sp[0] + " " + sp[1] + " L " + ep[0] + " " + ep[1]);
|
||
hi.setAttribute("pointer-events", "stroke");
|
||
path.setAttribute("d", "M " + sp[0] + " " + sp[1] + " L " + ep[0] + " " + ep[1]);
|
||
path.setAttribute("stroke-width", 2.0);
|
||
path.setAttribute("stroke-linecap", "round");
|
||
path.setAttribute("fill", "none");
|
||
if (dash) path.setAttribute("style", "stroke-dasharray:6,5");
|
||
if (mark) {
|
||
path.setAttribute("stroke", "#ff3300");
|
||
path.setAttribute("marker-end", "url(#arrow2)");
|
||
} else {
|
||
path.setAttribute("stroke", "gray");
|
||
path.setAttribute("marker-end", "url(#arrow1)");
|
||
}
|
||
line.appendChild(hi);
|
||
line.appendChild(path);
|
||
line.style.cursor = "crosshair";
|
||
if (id != "" && id != "GooFlow_tmp_line") {
|
||
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
||
//text.textContent=id;
|
||
line.appendChild(text);
|
||
var x = (ep[0] + sp[0]) / 2;
|
||
var y = (ep[1] + sp[1]) / 2;
|
||
text.setAttribute("text-anchor", "middle");
|
||
text.setAttribute("x", x);
|
||
text.setAttribute("y", y - 5);
|
||
line.style.cursor = "pointer";
|
||
text.style.cursor = "text";
|
||
}
|
||
} else {
|
||
line = document.createElement("v:polyline");
|
||
if (id != "") line.id = id;
|
||
//line.style.position="absolute";
|
||
line.points.value = sp[0] + "," + sp[1] + " " + ep[0] + "," + ep[1];
|
||
line.setAttribute("fromTo", sp[0] + "," + sp[1] + "," + ep[0] + "," + ep[1]);
|
||
line.strokeWeight = "1.2";
|
||
line.stroke.EndArrow = "Block";
|
||
line.style.cursor = "crosshair";
|
||
if (id != "" && id != "GooFlow_tmp_line") {
|
||
var text = document.createElement("div");
|
||
//text.innerHTML=id;
|
||
line.appendChild(text);
|
||
var x = (ep[0] - sp[0]) / 2;
|
||
var y = (ep[1] - sp[1]) / 2;
|
||
if (x < 0) x = x * -1;
|
||
if (y < 0) y = y * -1;
|
||
text.style.left = x + "px";
|
||
text.style.top = y - 6 + "px";
|
||
line.style.cursor = "pointer";
|
||
}
|
||
if (dash) line.stroke.dashstyle = "Dash";
|
||
if (mark) line.strokeColor = "#ff3300";
|
||
else line.strokeColor = "gray";
|
||
}
|
||
return line;
|
||
},
|
||
//画一条只有两个中点的折线
|
||
drawPoly: function(id, sp, m1, m2, ep, mark) {
|
||
var poly, strPath;
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
poly = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
||
var hi = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||
var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||
if (id != "") poly.setAttribute("id", id);
|
||
poly.setAttribute("from", sp[0] + "," + sp[1]);
|
||
poly.setAttribute("to", ep[0] + "," + ep[1]);
|
||
hi.setAttribute("visibility", "hidden");
|
||
hi.setAttribute("stroke-width", 9);
|
||
hi.setAttribute("fill", "none");
|
||
hi.setAttribute("stroke", "white");
|
||
strPath = "M " + sp[0] + " " + sp[1];
|
||
if (m1[0] != sp[0] || m1[1] != sp[1])
|
||
strPath += " L " + m1[0] + " " + m1[1];
|
||
if (m2[0] != ep[0] || m2[1] != ep[1])
|
||
strPath += " L " + m2[0] + " " + m2[1];
|
||
strPath += " L " + ep[0] + " " + ep[1];
|
||
hi.setAttribute("d", strPath);
|
||
hi.setAttribute("pointer-events", "stroke");
|
||
path.setAttribute("d", strPath);
|
||
path.setAttribute("stroke-width", 2.0);
|
||
path.setAttribute("stroke-linecap", "round");
|
||
path.setAttribute("fill", "none");
|
||
if (mark) {
|
||
path.setAttribute("stroke", "#ff3300");
|
||
path.setAttribute("marker-end", "url(#arrow2)");
|
||
} else {
|
||
path.setAttribute("stroke", "gray");
|
||
path.setAttribute("marker-end", "url(#arrow1)");
|
||
}
|
||
poly.appendChild(hi);
|
||
poly.appendChild(path);
|
||
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
||
//text.textContent=id;
|
||
poly.appendChild(text);
|
||
var x = (m2[0] + m1[0]) / 2;
|
||
var y = (m2[1] + m1[1]) / 2;
|
||
text.setAttribute("text-anchor", "middle");
|
||
text.setAttribute("x", x);
|
||
text.setAttribute("y", y - 5);
|
||
text.style.cursor = "text";
|
||
poly.style.cursor = "pointer";
|
||
} else {
|
||
poly = document.createElement("v:Polyline");
|
||
if (id != "") poly.id = id;
|
||
poly.filled = "false";
|
||
strPath = sp[0] + "," + sp[1];
|
||
if (m1[0] != sp[0] || m1[1] != sp[1])
|
||
strPath += " " + m1[0] + "," + m1[1];
|
||
if (m2[0] != ep[0] || m2[1] != ep[1])
|
||
strPath += " " + m2[0] + "," + m2[1];
|
||
strPath += " " + ep[0] + "," + ep[1];
|
||
poly.points.value = strPath;
|
||
poly.setAttribute("fromTo", sp[0] + "," + sp[1] + "," + ep[0] + "," + ep[1]);
|
||
poly.strokeWeight = "1.2";
|
||
poly.stroke.EndArrow = "Block";
|
||
var text = document.createElement("div");
|
||
//text.innerHTML=id;
|
||
poly.appendChild(text);
|
||
var x = (m2[0] - m1[0]) / 2;
|
||
var y = (m2[1] - m1[1]) / 2;
|
||
if (x < 0) x = x * -1;
|
||
if (y < 0) y = y * -1;
|
||
text.style.left = x + "px";
|
||
text.style.top = y - 4 + "px";
|
||
poly.style.cursor = "pointer";
|
||
if (mark) poly.strokeColor = "#ff3300";
|
||
else poly.strokeColor = "gray";
|
||
}
|
||
return poly;
|
||
},
|
||
//计算两个结点间要连直线的话,连线的开始坐标和结束坐标
|
||
calcStartEnd: function(n1, n2) {
|
||
var X_1, Y_1, X_2, Y_2;
|
||
//X判断:
|
||
var x11 = n1.left, x12 = n1.left + n1.width, x21 = n2.left, x22 = n2.left + n2.width;
|
||
//结点2在结点1左边
|
||
if (x11 >= x22) {
|
||
X_1 = x11;
|
||
X_2 = x22;
|
||
}
|
||
//结点2在结点1右边
|
||
else if (x12 <= x21) {
|
||
X_1 = x12;
|
||
X_2 = x21;
|
||
}
|
||
//结点2在结点1水平部分重合
|
||
else if (x11 <= x21 && x12 >= x21 && x12 <= x22) {
|
||
X_1 = (x12 + x21) / 2;
|
||
X_2 = X_1;
|
||
} else if (x11 >= x21 && x12 <= x22) {
|
||
X_1 = (x11 + x12) / 2;
|
||
X_2 = X_1;
|
||
} else if (x21 >= x11 && x22 <= x12) {
|
||
X_1 = (x21 + x22) / 2;
|
||
X_2 = X_1;
|
||
} else if (x11 <= x22 && x12 >= x22) {
|
||
X_1 = (x11 + x22) / 2;
|
||
X_2 = X_1;
|
||
}
|
||
|
||
//Y判断:
|
||
var y11 = n1.top, y12 = n1.top + n1.height, y21 = n2.top, y22 = n2.top + n2.height;
|
||
//结点2在结点1上边
|
||
if (y11 >= y22) {
|
||
Y_1 = y11;
|
||
Y_2 = y22;
|
||
}
|
||
//结点2在结点1下边
|
||
else if (y12 <= y21) {
|
||
Y_1 = y12;
|
||
Y_2 = y21;
|
||
}
|
||
//结点2在结点1垂直部分重合
|
||
else if (y11 <= y21 && y12 >= y21 && y12 <= y22) {
|
||
Y_1 = (y12 + y21) / 2;
|
||
Y_2 = Y_1;
|
||
} else if (y11 >= y21 && y12 <= y22) {
|
||
Y_1 = (y11 + y12) / 2;
|
||
Y_2 = Y_1;
|
||
} else if (y21 >= y11 && y22 <= y12) {
|
||
Y_1 = (y21 + y22) / 2;
|
||
Y_2 = Y_1;
|
||
} else if (y11 <= y22 && y12 >= y22) {
|
||
Y_1 = (y11 + y22) / 2;
|
||
Y_2 = Y_1;
|
||
}
|
||
return { "start": [X_1, Y_1], "end": [X_2, Y_2] };
|
||
},
|
||
//计算两个结点间要连折线的话,连线的所有坐标
|
||
calcPolyPoints: function(n1, n2, type, M) {
|
||
//开始/结束两个结点的中心
|
||
var SP = { x: n1.left + n1.width / 2, y: n1.top + n1.height / 2 };
|
||
var EP = { x: n2.left + n2.width / 2, y: n2.top + n2.height / 2 };
|
||
var sp = [], m1 = [], m2 = [], ep = [];
|
||
//如果是允许中段可左右移动的折线,则参数M为可移动中段线的X坐标
|
||
//粗略计算起始点
|
||
sp = [SP.x, SP.y];
|
||
ep = [EP.x, EP.y];
|
||
if (type == "lr") {
|
||
//粗略计算2个中点
|
||
m1 = [M, SP.y];
|
||
m2 = [M, EP.y];
|
||
//再具体分析修改开始点和中点1
|
||
if (m1[0] > n1.left && m1[0] < n1.left + n1.width) {
|
||
m1[1] = (SP.y > EP.y ? n1.top : n1.top + n1.height);
|
||
sp[0] = m1[0];
|
||
sp[1] = m1[1];
|
||
} else {
|
||
sp[0] = (m1[0] < n1.left ? n1.left : n1.left + n1.width)
|
||
}
|
||
//再具体分析中点2和结束点
|
||
if (m2[0] > n2.left && m2[0] < n2.left + n2.width) {
|
||
m2[1] = (SP.y > EP.y ? n2.top + n2.height : n2.top);
|
||
ep[0] = m2[0];
|
||
ep[1] = m2[1];
|
||
} else {
|
||
ep[0] = (m2[0] < n2.left ? n2.left : n2.left + n2.width)
|
||
}
|
||
}
|
||
//如果是允许中段可上下移动的折线,则参数M为可移动中段线的Y坐标
|
||
else if (type == "tb") {
|
||
//粗略计算2个中点
|
||
m1 = [SP.x, M];
|
||
m2 = [EP.x, M];
|
||
//再具体分析修改开始点和中点1
|
||
if (m1[1] > n1.top && m1[1] < n1.top + n1.height) {
|
||
m1[0] = (SP.x > EP.x ? n1.left : n1.left + n1.width);
|
||
sp[0] = m1[0];
|
||
sp[1] = m1[1];
|
||
} else {
|
||
sp[1] = (m1[1] < n1.top ? n1.top : n1.top + n1.height)
|
||
}
|
||
//再具体分析中点2和结束点
|
||
if (m2[1] > n2.top && m2[1] < n2.top + n2.height) {
|
||
m2[0] = (SP.x > EP.x ? n2.left + n2.width : n2.left);
|
||
ep[0] = m2[0];
|
||
ep[1] = m2[1];
|
||
} else {
|
||
ep[1] = (m2[1] < n2.top ? n2.top : n2.top + n2.height);
|
||
}
|
||
}
|
||
return { start: sp, m1: m1, m2: m2, end: ep };
|
||
},
|
||
//初始化折线中段的X/Y坐标,mType='rb'时为X坐标,mType='tb'时为Y坐标
|
||
getMValue: function(n1, n2, mType) {
|
||
if (mType == "lr") {
|
||
return (n1.left + n1.width / 2 + n2.left + n2.width / 2) / 2;
|
||
} else if (mType == "tb") {
|
||
return (n1.top + n1.height / 2 + n2.top + n2.height / 2) / 2;
|
||
}
|
||
},
|
||
//增加一条线
|
||
addLine: function(id, json) {
|
||
if (this.onItemAdd != null && !this.onItemAdd(id, "line", json)) return;
|
||
if (this.$undoStack && this.$editable) {
|
||
this.pushOper("delLine", [id]);
|
||
}
|
||
var n1 = null, n2 = null; //获取开始/结束结点的数据
|
||
if (json.from == json.to) return;
|
||
//避免两个节点间不能有一条以上同向接连线
|
||
for (var k in this.$lineData) {
|
||
if ((json.from == this.$lineData[k].from && json.to == this.$lineData[k].to))
|
||
return;
|
||
}
|
||
var n1 = this.$nodeData[json.from], n2 = this.$nodeData[json.to]; //获取开始/结束结点的数据
|
||
if (!n1 || !n2) return;
|
||
var res;
|
||
if (json.type && json.type != "sl")
|
||
res = GooFlow.prototype.calcPolyPoints(n1, n2, json.type, json.M);
|
||
else
|
||
res = GooFlow.prototype.calcStartEnd(n1, n2);
|
||
if (!res) return;
|
||
this.$lineData[id] = {};
|
||
this.$lineData[id].setInfo = json.setInfo;
|
||
this.$lineData[id].id = json.id;
|
||
if (json.type) {
|
||
this.$lineData[id].type = json.type;
|
||
this.$lineData[id].M = json.M;
|
||
} else this.$lineData[id].type = "sl"; //默认为直线
|
||
this.$lineData[id].from = json.from;
|
||
this.$lineData[id].to = json.to;
|
||
this.$lineData[id].name = json.name;
|
||
if (json.mark) this.$lineData[id].marked = json.mark;
|
||
else this.$lineData[id].marked = false;
|
||
|
||
if (this.$lineData[id].type == "sl")
|
||
this.$lineDom[id] = GooFlow.prototype.drawLine(id, res.start, res.end, json.mark);
|
||
else
|
||
this.$lineDom[id] = GooFlow.prototype.drawPoly(id, res.start, res.m1, res.m2, res.end, json.mark);
|
||
this.$draw.appendChild(this.$lineDom[id]);
|
||
if (GooFlow.prototype.useSVG == "") {
|
||
this.$lineDom[id].childNodes[1].innerHTML = json.name;
|
||
if (this.$lineData[id].type != "sl") {
|
||
var Min = (res.start[0] > res.end[0] ? res.end[0] : res.start[0]);
|
||
if (Min > res.m2[0]) Min = res.m2[0];
|
||
if (Min > res.m1[0]) Min = res.m1[0];
|
||
this.$lineDom[id].childNodes[1].style.left = (res.m2[0] + res.m1[0]) / 2 -
|
||
Min -
|
||
this.$lineDom[id].childNodes[1].offsetWidth / 2 +
|
||
4;
|
||
Min = (res.start[1] > res.end[1] ? res.end[1] : res.start[1]);
|
||
if (Min > res.m2[1]) Min = res.m2[1];
|
||
if (Min > res.m1[1]) Min = res.m1[1];
|
||
this.$lineDom[id].childNodes[1].style.top = (res.m2[1] + res.m1[1]) / 2 -
|
||
Min -
|
||
this.$lineDom[id].childNodes[1].offsetHeight / 2;
|
||
} else
|
||
this.$lineDom[id].childNodes[1].style.left =
|
||
((res.end[0] - res.start[0]) * (res.end[0] > res.start[0] ? 1 : -1) -
|
||
this.$lineDom[id].childNodes[1].offsetWidth) /
|
||
2 +
|
||
4;
|
||
} else this.$lineDom[id].childNodes[2].textContent = json.name;
|
||
++this.$lineCount;
|
||
if (this.$editable) {
|
||
this.$lineData[id].alt = true;
|
||
if (this.$deletedItem[id]) delete this.$deletedItem[id]; //在回退删除操作时,去掉该元素的删除记录
|
||
}
|
||
},
|
||
//重构所有连向某个结点的线的显示,传参结构为$nodeData数组的一个单元结构
|
||
resetLines: function(id, node) {
|
||
for (var i in this.$lineData) {
|
||
var other = null; //获取结束/开始结点的数据
|
||
var res;
|
||
if (this.$lineData[i].from == id) { //找结束点
|
||
other = this.$nodeData[this.$lineData[i].to] || null;
|
||
if (other == null) continue;
|
||
if (this.$lineData[i].type == "sl")
|
||
res = GooFlow.prototype.calcStartEnd(node, other);
|
||
else
|
||
res = GooFlow.prototype.calcPolyPoints(node,
|
||
other,
|
||
this.$lineData[i].type,
|
||
this.$lineData[i].M)
|
||
if (!res) break;
|
||
} else if (this.$lineData[i].to == id) { //找开始点
|
||
other = this.$nodeData[this.$lineData[i].from] || null;
|
||
if (other == null) continue;
|
||
if (this.$lineData[i].type == "sl")
|
||
res = GooFlow.prototype.calcStartEnd(other, node);
|
||
else
|
||
res = GooFlow.prototype.calcPolyPoints(other,
|
||
node,
|
||
this.$lineData[i].type,
|
||
this.$lineData[i].M);
|
||
if (!res) break;
|
||
}
|
||
if (other == null) continue;
|
||
this.$draw.removeChild(this.$lineDom[i]);
|
||
if (this.$lineData[i].type == "sl") {
|
||
this.$lineDom[i] = GooFlow.prototype.drawLine(i, res.start, res.end, this.$lineData[i].marked);
|
||
} else {
|
||
this.$lineDom[i] =
|
||
GooFlow.prototype.drawPoly(i, res.start, res.m1, res.m2, res.end, this.$lineData[i].marked);
|
||
}
|
||
this.$draw.appendChild(this.$lineDom[i]);
|
||
if (GooFlow.prototype.useSVG == "") {
|
||
this.$lineDom[i].childNodes[1].innerHTML = this.$lineData[i].name;
|
||
if (this.$lineData[i].type != "sl") {
|
||
var Min = (res.start[0] > res.end[0] ? res.end[0] : res.start[0]);
|
||
if (Min > res.m2[0]) Min = res.m2[0];
|
||
if (Min > res.m1[0]) Min = res.m1[0];
|
||
this.$lineDom[i].childNodes[1].style.left = (res.m2[0] + res.m1[0]) / 2 -
|
||
Min -
|
||
this.$lineDom[i].childNodes[1].offsetWidth / 2 +
|
||
4;
|
||
Min = (res.start[1] > res.end[1] ? res.end[1] : res.start[1]);
|
||
if (Min > res.m2[1]) Min = res.m2[1];
|
||
if (Min > res.m1[1]) Min = res.m1[1];
|
||
this.$lineDom[i].childNodes[1].style.top = (res.m2[1] + res.m1[1]) / 2 -
|
||
Min -
|
||
this.$lineDom[i].childNodes[1].offsetHeight / 2 -
|
||
4;
|
||
} else
|
||
this.$lineDom[i].childNodes[1].style.left =
|
||
((res.end[0] - res.start[0]) * (res.end[0] > res.start[0] ? 1 : -1) -
|
||
this.$lineDom[i].childNodes[1].offsetWidth) /
|
||
2 +
|
||
4;
|
||
} else this.$lineDom[i].childNodes[2].textContent = this.$lineData[i].name;
|
||
}
|
||
},
|
||
//重新设置连线的样式 newType= "sl":直线, "lr":中段可左右移动型折线, "tb":中段可上下移动型折线
|
||
setLineType: function(id, newType) {
|
||
if (!newType || newType == null || newType == "" || newType == this.$lineData[id].type) return false;
|
||
if (this.onLineSetType != null && !this.onLineSetType(id, newType)) return;
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$lineData[id].type];
|
||
this.pushOper("setLineType", paras);
|
||
if (this.$lineData[id].type != "sl") {
|
||
var para2 = [id, this.$lineData[id].M];
|
||
this.pushOper("setLineM", para2);
|
||
}
|
||
}
|
||
var from = this.$lineData[id].from;
|
||
var to = this.$lineData[id].to;
|
||
this.$lineData[id].type = newType;
|
||
var res;
|
||
//如果是变成折线
|
||
if (newType != "sl") {
|
||
var res = GooFlow.prototype.calcPolyPoints(this.$nodeData[from],
|
||
this.$nodeData[to],
|
||
this.$lineData[id].type,
|
||
this.$lineData[id].M);
|
||
this.setLineM(id, this.getMValue(this.$nodeData[from], this.$nodeData[to], newType), true);
|
||
}
|
||
//如果是变回直线
|
||
else {
|
||
delete this.$lineData[id].M;
|
||
this.$lineMove.hide().removeData("type").removeData("tid");
|
||
res = GooFlow.prototype.calcStartEnd(this.$nodeData[from], this.$nodeData[to]);
|
||
if (!res) return;
|
||
this.$draw.removeChild(this.$lineDom[id]);
|
||
this.$lineDom[id] = GooFlow.prototype.drawLine(id,
|
||
res.start,
|
||
res.end,
|
||
this.$lineData[id].marked || this.$focus == id);
|
||
this.$draw.appendChild(this.$lineDom[id]);
|
||
if (GooFlow.prototype.useSVG == "") {
|
||
this.$lineDom[id].childNodes[1].innerHTML = this.$lineData[id].name;
|
||
this.$lineDom[id].childNodes[1].style.left =
|
||
((res.end[0] - res.start[0]) * (res.end[0] > res.start[0] ? 1 : -1) -
|
||
this.$lineDom[id].childNodes[1].offsetWidth) /
|
||
2 +
|
||
4;
|
||
} else
|
||
this.$lineDom[id].childNodes[2].textContent = this.$lineData[id].name;
|
||
}
|
||
if (this.$focus == id) {
|
||
this.focusItem(id);
|
||
}
|
||
if (this.$editable) {
|
||
this.$lineData[id].alt = true;
|
||
}
|
||
},
|
||
//设置折线中段的X坐标值(可左右移动时)或Y坐标值(可上下移动时)
|
||
setLineM: function(id, M, noStack) {
|
||
if (!this.$lineData[id] || M < 0 || !this.$lineData[id].type || this.$lineData[id].type == "sl")
|
||
return false;
|
||
if (this.onLineMove != null && !this.onLineMove(id, M)) return false;
|
||
if (this.$undoStack && !noStack) {
|
||
var paras = [id, this.$lineData[id].M];
|
||
this.pushOper("setLineM", paras);
|
||
}
|
||
var from = this.$lineData[id].from;
|
||
var to = this.$lineData[id].to;
|
||
this.$lineData[id].M = M;
|
||
var ps = GooFlow.prototype.calcPolyPoints(this.$nodeData[from],
|
||
this.$nodeData[to],
|
||
this.$lineData[id].type,
|
||
this.$lineData[id].M);
|
||
this.$draw.removeChild(this.$lineDom[id]);
|
||
this.$lineDom[id] = GooFlow.prototype.drawPoly(id,
|
||
ps.start,
|
||
ps.m1,
|
||
ps.m2,
|
||
ps.end,
|
||
this.$lineData[id].marked || this.$focus == id);
|
||
this.$draw.appendChild(this.$lineDom[id]);
|
||
if (GooFlow.prototype.useSVG == "") {
|
||
this.$lineDom[id].childNodes[1].innerHTML = this.$lineData[id].name;
|
||
var Min = (ps.start[0] > ps.end[0] ? ps.end[0] : ps.start[0]);
|
||
if (Min > ps.m2[0]) Min = ps.m2[0];
|
||
if (Min > ps.m1[0]) Min = ps.m1[0];
|
||
this.$lineDom[id].childNodes[1].style.left = (ps.m2[0] + ps.m1[0]) / 2 -
|
||
Min -
|
||
this.$lineDom[id].childNodes[1].offsetWidth / 2 +
|
||
4;
|
||
Min = (ps.start[1] > ps.end[1] ? ps.end[1] : ps.start[1]);
|
||
if (Min > ps.m2[1]) Min = ps.m2[1];
|
||
if (Min > ps.m1[1]) Min = ps.m1[1];
|
||
this.$lineDom[id].childNodes[1].style.top = (ps.m2[1] + ps.m1[1]) / 2 -
|
||
Min -
|
||
this.$lineDom[id].childNodes[1].offsetHeight / 2 -
|
||
4;
|
||
} else this.$lineDom[id].childNodes[2].textContent = this.$lineData[id].name;
|
||
if (this.$editable) {
|
||
this.$lineData[id].alt = true;
|
||
}
|
||
},
|
||
//删除转换线
|
||
delLine: function(id) {
|
||
if (!this.$lineData[id]) return;
|
||
if (this.onItemDel != null && !this.onItemDel(id, "node")) return;
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$lineData[id]];
|
||
this.pushOper("addLine", paras);
|
||
}
|
||
this.$draw.removeChild(this.$lineDom[id]);
|
||
delete this.$lineData[id];
|
||
delete this.$lineDom[id];
|
||
if (this.$focus == id) this.$focus = "";
|
||
--this.$lineCount;
|
||
if (this.$editable) {
|
||
//在回退新增操作时,如果节点ID以this.$id+"_line_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
|
||
if (id.indexOf(this.$id + "_line_") < 0)
|
||
this.$deletedItem[id] = "line";
|
||
}
|
||
this.$lineOper.hide();
|
||
},
|
||
//用颜色标注/取消标注一个结点或转换线,常用于显示重点或流程的进度。
|
||
//这是一个在编辑模式中无用,但是在纯浏览模式中非常有用的方法,实际运用中可用于跟踪流程的进度。
|
||
markItem: function(id, type, mark) {
|
||
if (type == "node") {
|
||
if (!this.$nodeData[id]) return;
|
||
if (this.onItemMark != null && !this.onItemMark(id, "node", mark)) return;
|
||
this.$nodeData[id].marked = mark || false;
|
||
if (mark) this.$nodeDom[id].addClass("item_mark");
|
||
else this.$nodeDom[id].removeClass("item_mark");
|
||
|
||
} else if (type == "line") {
|
||
if (!this.$lineData[id]) return;
|
||
if (this.onItemMark != null && !this.onItemMark(id, "line", mark)) return;
|
||
this.$lineData[id].marked = mark || false;
|
||
if (GooFlow.prototype.useSVG != "") {
|
||
if (mark) {
|
||
this.$nodeDom[id].childNodes[1].setAttribute("stroke", "#ff3300");
|
||
this.$nodeDom[id].childNodes[1].setAttribute("marker-end", "url(#arrow2)");
|
||
} else {
|
||
this.$nodeDom[id].childNodes[1].setAttribute("stroke", "gray");
|
||
this.$nodeDom[id].childNodes[1].setAttribute("marker-end", "url(#arrow1)");
|
||
}
|
||
} else {
|
||
if (mark) this.$nodeDom[id].strokeColor = "#ff3300";
|
||
else this.$nodeDom[id].strokeColor = "gray"
|
||
}
|
||
}
|
||
if (this.$undoStatck) {
|
||
var paras = [id, type, !mark];
|
||
this.pushOper("markItem", paras);
|
||
}
|
||
},
|
||
////////////////////////以下为区域分组块操作
|
||
moveArea: function(id, left, top) {
|
||
if (!this.$areaData[id]) return;
|
||
if (this.onItemMove != null && !this.onItemMove(id, "area", left, top)) return;
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$areaData[id].left, this.$areaData[id].top];
|
||
this.pushOper("moveNode", paras);
|
||
}
|
||
if (left < 0) left = 0;
|
||
if (top < 0) top = 0;
|
||
$("#" + id).css({ left: left + "px", top: top + "px" });
|
||
this.$areaData[id].left = left;
|
||
this.$areaData[id].top = top;
|
||
if (this.$editable) {
|
||
this.$areaData[id].alt = true;
|
||
}
|
||
},
|
||
//删除区域分组
|
||
delArea: function(id) {
|
||
if (!this.$areaData[id]) return;
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$areaData[id]];
|
||
this.pushOper("addArea", paras);
|
||
}
|
||
if (this.onItemDel != null && !this.onItemDel(id, "node")) return;
|
||
delete this.$areaData[id];
|
||
this.$areaDom[id].remove();
|
||
delete this.$areaDom[id];
|
||
--this.$areaCount;
|
||
if (this.$editable) {
|
||
//在回退新增操作时,如果节点ID以this.$id+"_area_"开头,则表示为本次编辑时新加入的节点,这些节点的删除不用加入到$deletedItem中
|
||
if (id.indexOf(this.$id + "_area_") < 0)
|
||
this.$deletedItem[id] = "area";
|
||
}
|
||
},
|
||
//设置区域分组的颜色
|
||
setAreaColor: function(id, color) {
|
||
if (!this.$areaData[id]) return;
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$areaData[id].color];
|
||
this.pushOper("setAreaColor", paras);
|
||
}
|
||
if (color == "red" || color == "yellow" || color == "blue" || color == "green") {
|
||
this.$areaDom[id].removeClass("area_" + this.$areaData[id].color).addClass("area_" + color);
|
||
this.$areaData[id].color = color;
|
||
}
|
||
if (this.$editable) {
|
||
this.$areaData[id].alt = true;
|
||
}
|
||
},
|
||
//设置区域分块的尺寸
|
||
resizeArea: function(id, width, height) {
|
||
if (!this.$areaData[id]) return;
|
||
if (this.onItemResize != null && !this.onItemResize(id, "area", width, height)) return;
|
||
if (this.$undoStack) {
|
||
var paras = [id, this.$areaData[id].width, this.$areaData[id].height];
|
||
this.pushOper("resizeArea", paras);
|
||
}
|
||
var hack = 0;
|
||
if (navigator.userAgent.indexOf("8.0") != -1) hack = 2;
|
||
this.$areaDom[id].children(".bg").css({ width: width - 2 + "px", height: height - 2 + "px" });
|
||
width = this.$areaDom[id].outerWidth();
|
||
height = this.$areaDom[id].outerHeight();
|
||
this.$areaDom[id].children("bg").css({ width: width - 2 + "px", height: height - 2 + "px" });
|
||
this.$areaData[id].width = width;
|
||
this.$areaData[id].height = height;
|
||
if (this.$editable) {
|
||
this.$areaData[id].alt = true;
|
||
}
|
||
},
|
||
addArea: function(id, json) {
|
||
if (this.onItemAdd != null && !this.onItemAdd(id, "area", json)) return;
|
||
if (this.$undoStack && this.$editable) {
|
||
this.pushOper("delArea", [id]);
|
||
}
|
||
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>" +
|
||
"<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>");
|
||
this.$areaData[id] = json;
|
||
this.$group.append(this.$areaDom[id]);
|
||
if (this.$nowType != "group") this.$areaDom[id].children("div:eq(1)").css("display", "none");
|
||
++this.$areaCount;
|
||
if (this.$editable) {
|
||
this.$areaData[id].alt = true;
|
||
if (this.$deletedItem[id]) delete this.$deletedItem[id]; //在回退删除操作时,去掉该元素的删除记录
|
||
}
|
||
},
|
||
//重构整个流程图设计器的宽高
|
||
reinitSize: function(width, height) {
|
||
var w = (width || 800) - 2;
|
||
var h = (height || 500) - 2;
|
||
this.$bgDiv.css({ height: h + "px", width: w + "px" });
|
||
var headHeight = 0, hack = 10;
|
||
if (this.$head != null) {
|
||
headHeight = 24;
|
||
hack = 7;
|
||
}
|
||
if (this.$tool != null) {
|
||
this.$tool.css({ height: h - headHeight - hack + "px" });
|
||
}
|
||
w -= 39;
|
||
h = h - headHeight - (this.$head != null ? 5 : 8);
|
||
this.$workArea.parent().css({ height: h + "px", width: w + "px" });
|
||
this.$workArea.css({ height: h * 3 + "px", width: w * 3 + "px" });
|
||
if (GooFlow.prototype.useSVG == "") {
|
||
this.$draw.coordsize = w * 3 + "," + h * 3;
|
||
}
|
||
this.$draw.style.width = w * 3 + "px";
|
||
this.$draw.style.height = +h * 3 + "px";
|
||
if (this.$group == null) {
|
||
this.$group.css({ height: h * 3 + "px", width: w * 3 + "px" });
|
||
}
|
||
}
|
||
}
|
||
//将此类的构造函数加入至JQUERY对象中
|
||
jQuery.extend({
|
||
createGooFlow: function(bgDiv, property) {
|
||
return new GooFlow(bgDiv, property);
|
||
}
|
||
});
|
||
|
||
//获取一个DIV的绝对坐标的功能函数,即使是非绝对定位,一样能获取到
|
||
function getElCoordinate(dom) {
|
||
var t = dom.offsetTop;
|
||
var l = dom.offsetLeft;
|
||
dom = dom.offsetParent;
|
||
while (dom) {
|
||
t += dom.offsetTop;
|
||
l += dom.offsetLeft;
|
||
dom = dom.offsetParent;
|
||
};
|
||
return {
|
||
top: t,
|
||
left: l
|
||
};
|
||
}
|
||
|
||
//兼容各种浏览器的,获取鼠标真实位置
|
||
function mousePosition(ev) {
|
||
if (!ev) ev = window.event;
|
||
if (ev.pageX || ev.pageY) {
|
||
return { x: ev.pageX, y: ev.pageY };
|
||
}
|
||
return {
|
||
x: ev.clientX + document.documentElement.scrollLeft - document.body.clientLeft,
|
||
y: ev.clientY + document.documentElement.scrollTop - document.body.clientTop
|
||
};
|
||
}
|
||
|
||
exports('flow-ui/gooflow');
|
||
});
|
||
|