// 定义一个区域图类:
|
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')
|
if (GooFlow.prototype.color.font) {
|
this.$bgDiv.css('color', GooFlow.prototype.color.font)
|
}
|
if (GooFlow.prototype.color.main) {
|
this.$bgDiv.append(
|
'<style>.GooFlow_tool_btndown{background:' +
|
GooFlow.prototype.color.main +
|
'}</style>'
|
)
|
}
|
var width = property.width || 800
|
var height = property.height || 500
|
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
|
this.$workExtendStep = 200 // 在自动/手动扩展可编辑区时,一次扩展后宽/高增加多少像素
|
var headHeight = 0
|
var tmp = ''
|
|
if (property.haveHead) {
|
tmp =
|
"<div class='GooFlow_head' " +
|
(GooFlow.prototype.color.main
|
? "style='border-bottom-color:" + GooFlow.prototype.color.main + "'"
|
: '') +
|
'>'
|
if (property.headLabel) {
|
tmp +=
|
"<label title='" +
|
(property.initLabelText || 'newFlow_1') +
|
"' " +
|
(GooFlow.prototype.color.main
|
? "style='background:" + GooFlow.prototype.color.main + "'"
|
: '') +
|
'>' +
|
(property.initLabelText || 'newFlow_1') +
|
'</label>'
|
}
|
for (var x = 0; x < property.headBtns.length; ++x) {
|
tmp +=
|
"<a href='javascript:void(0)' class='GooFlow_head_btn'><i class='ico_" +
|
property.headBtns[x] +
|
'\'></i></a>'
|
}
|
tmp += '</div>'
|
this.$head = $(tmp)
|
this.$bgDiv.append(this.$head)
|
headHeight = 28
|
// 以下是当工具栏按钮被点击时触发的事件自定义(虚函数),格式为function(),因为可直接用THIS操作对象本身,不用传参;用户可自行重定义:
|
this.onBtnNewClick = null // 新建流程图按钮被点中
|
this.onBtnOpenClick = null // 打开流程图按钮定义
|
this.onBtnSaveClick = null // 保存流程图按钮定义
|
this.onFreshClick = null // 重载流程图按钮定义
|
this.onPrintClick = 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.childNodes[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
|
case 'ico_print':
|
if (This.onPrintClick != null) This.onPrintClick()
|
break
|
}
|
})
|
}
|
var toolWidth = 0
|
if (property.haveTool) {
|
this.$bgDiv.append(
|
"<div class='GooFlow_tool'" +
|
(property.haveHead ? '' : " style='margin-top:4px'") +
|
"><div style='height:" +
|
(height - headHeight - (property.haveHead ? 5 : 8)) +
|
"px' class='GooFlow_tool_div'></div></div>"
|
)
|
this.$tool = this.$bgDiv.find('.GooFlow_tool div')
|
// 未加代码:加入绘图工具按钮
|
this.$tool.append(
|
"<div style='margin-bottom:5px'><span/><span/><span/><span/></div>" +
|
"<a href='javascript:void(0)' type='cursor' class='GooFlow_tool_btndown' id='" +
|
this.$id +
|
"_btn_cursor'><i class='ico_cursor'/></a>" +
|
"<a href='javascript:void(0)' type='direct' class='GooFlow_tool_btn' id='" +
|
this.$id +
|
'_btn_direct\'><i class=\'ico_direct\'/></a>'
|
)
|
if (property.toolBtns && property.toolBtns.length > 0) {
|
tmp = '<span/>'
|
for (var i = 0; i < property.toolBtns.length; ++i) {
|
tmp +=
|
"<a href='javascript:void(0)' type='" +
|
property.toolBtns[i] +
|
"' id='" +
|
this.$id +
|
'_btn_' +
|
property.toolBtns[i].split(' ')[0] +
|
"' class='GooFlow_tool_btn'><i class='ico_" +
|
property.toolBtns[i] +
|
"'/></a>" // 加入自定义按钮
|
}
|
this.$tool.append(tmp)
|
}
|
// 加入区域划分框工具开关按钮
|
if (property.haveGroup)
|
this.$tool.append(
|
"<span/><a href='javascript:void(0)' type='group' class='GooFlow_tool_btn' id='" +
|
this.$id +
|
"_btn_group'><i 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 'I':
|
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 - 9
|
height = height - headHeight - (property.haveHead ? 5 : 8)
|
this.$bgDiv.append(
|
"<div class='GooFlow_work' style='width:" +
|
width +
|
'px;height:' +
|
height +
|
'px;' +
|
(property.haveHead ? '' : 'margin-top:3px') +
|
"'></div>"
|
)
|
this.$workArea = $(
|
"<div class='GooFlow_work_inner' style='width:" +
|
width +
|
'px;height:' +
|
height +
|
"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)
|
this.initExpendFunc()
|
|
if (this.$editable) {
|
// 绑定工作区事件
|
this.$workArea.on('click', { inthis: this }, function(e) {
|
if (!e) e = window.event
|
var This = e.data.inthis
|
if (!This.$editable) return
|
var type = This.$nowType
|
if (type == 'cursor') {
|
var t = $(e.target)
|
var n = t.prop('tagName')
|
// alert(n);
|
if (
|
n == 'svg' ||
|
(n == 'DIV' && t.prop('class').indexOf('GooFlow_work') > -1) ||
|
n == 'LABEL'
|
) {
|
if (This.$lineOper.data('tid')) {
|
This.focusItem(This.$lineOper.data('tid'), false)
|
// This.$mpFrom.removeData("p");
|
} else {
|
This.blurItem()
|
}
|
}
|
return
|
} else if (type == 'direct' || type == 'group') return
|
var X, Y
|
var ev = mousePosition(e)
|
var t = getElCoordinate(this)
|
X = ev.x - t.left + this.parentNode.scrollLeft
|
Y = ev.y - t.top + this.parentNode.scrollTop
|
This.addNode(new Date().getTime(), {
|
name: 'node_' + This.$max,
|
left: X,
|
top: Y,
|
type: This.$nowType
|
})
|
This.$max++
|
})
|
// 划线或改线时用的绑定
|
this.$workArea.mousemove({ inthis: this }, function(e) {
|
if (e.data.inthis.$nowType != 'direct' && !e.data.inthis.$mpTo.data('p'))
|
return
|
var lineStart = $(this).data('lineStart')
|
var lineEnd = $(this).data('lineEnd')
|
if (!lineStart && !lineEnd) return
|
|
var ev = mousePosition(e)
|
var 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 (lineStart) {
|
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
|
} else if (lineEnd) {
|
if (GooFlow.prototype.useSVG != '') {
|
line.childNodes[0].setAttribute(
|
'd',
|
'M ' + X + ' ' + Y + ' L ' + lineEnd.x + ' ' + lineEnd.y
|
)
|
line.childNodes[1].setAttribute(
|
'd',
|
'M ' + X + ' ' + Y + ' L ' + lineEnd.x + ' ' + lineEnd.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 = X + ',' + Y + ' ' + lineEnd.x + ',' + lineEnd.y
|
}
|
})
|
this.$workArea.mouseup({ inthis: this }, function(e) {
|
var This = e.data.inthis
|
if (This.$nowType != 'direct' && !This.$mpTo.data('p')) return
|
var tmp = document.getElementById('GooFlow_tmp_line')
|
if (tmp) {
|
$(this)
|
.css('cursor', 'auto')
|
.removeData('lineStart')
|
.removeData('lineEnd')
|
This.$mpTo.hide().removeData('p')
|
This.$mpFrom.hide().removeData('p')
|
This.$draw.removeChild(tmp)
|
This.focusItem(This.$focus, false)
|
} else {
|
This.$lineOper.removeData('tid')
|
}
|
})
|
// 为了结点而增加的一些集体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_linemove" 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)
|
var t = getElCoordinateOveride(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
|
var 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'><i class='b_l1'></i><i class='b_l2'></i><i class='b_l3'></i><i class='b_x'></i></div>"
|
) // 选定线时显示的操作框
|
this.$workArea.parent().append(this.$lineOper)
|
this.$lineOper.on('click', { inthis: this }, function(e) {
|
if (!e) e = window.event
|
if (e.target.tagName != 'I') 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
|
}
|
})
|
// 新增移动线两个端点至新的结点功能移动功能,这里要提供移动用的DOM
|
this.$mpFrom = $("<div class='GooFlow_line_mp' style='display:none'></div>")
|
this.$mpTo = $("<div class='GooFlow_line_mp' style='display:none'></div>")
|
this.$workArea.append(this.$mpFrom).append(this.$mpTo)
|
this.initLinePointsChg()
|
|
// 下面绑定当结点/线/分组块的一些操作事件,这些事件可直接通过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,newStart,newEnd):id是连线单元的唯一标识ID,newStart,newEnd分别是起始结点的ID和到达结点的ID
|
this.onLinePointMove = null
|
// 当用重色标注某个结点/转换线时触发的方法,返回FALSE可阻止重定大小/造型事件的发生
|
// 格式function(id,type,mark):id是单元的唯一标识ID,type是单元类型("node"结点,"line"转换线),mark为布尔值,表示是要标注TRUE还是取消标注FALSE
|
this.onItemMark = null
|
this.onItemDbClick = 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
|
this.blurItem()
|
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
|
this.blurItem()
|
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',
|
GooFlow.prototype.color.line || '#3892D3'
|
)
|
)
|
defs.appendChild(
|
GooFlow.prototype.getSvgMarker(
|
'arrow2',
|
GooFlow.prototype.color.mark || '#ff8800'
|
)
|
)
|
defs.appendChild(
|
GooFlow.prototype.getSvgMarker(
|
'arrow3',
|
GooFlow.prototype.color.mark || '#ff8800'
|
)
|
)
|
} else {
|
this.$draw = document.createElement('v:group')
|
this.$draw.coordsize = width + ',' + height
|
this.$workArea.prepend(
|
"<div class='GooFlow_work_vml' style='position:relative;width:" +
|
width +
|
'px;height:' +
|
height +
|
"px'></div>"
|
)
|
this.$workArea.children('div')[0].insertBefore(this.$draw, null)
|
}
|
this.$draw.id = id
|
this.$draw.style.width = width + 'px'
|
this.$draw.style.height = +height + 'px'
|
// 绑定连线的点击选中以及双击编辑事件
|
var tmpClk = null
|
if (GooFlow.prototype.useSVG != '') tmpClk = 'g'
|
else tmpClk = 'PolyLine'
|
if (!this.$editable) return
|
|
$(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 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 - 64
|
y = (parseInt(from[1], 10) + parseInt(to[1], 10)) / 2 - 18
|
var t = getElCoordinateOveride(This.$workArea[0])
|
This.$textArea
|
.val(oldTxt)
|
.css({
|
display: 'block',
|
width: 130,
|
height: 26,
|
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 +
|
'px;height:' +
|
height +
|
"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 (!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 ev = mousePosition(e)
|
var t = getElCoordinateOveride(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 + 'px',
|
height: This.$areaData[id].height + 'px',
|
top:
|
This.$areaData[id].top +
|
t.top -
|
This.$workArea[0].parentNode.scrollTop +
|
'px',
|
left:
|
This.$areaData[id].left +
|
t.left -
|
This.$workArea[0].parentNode.scrollLeft +
|
'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 + 'px', height: Y + 'px' })
|
break
|
case 'w-resize':
|
This.$ghost.css({ width: X + 'px' })
|
break
|
case 'n-resize':
|
This.$ghost.css({ height: Y + 'px' })
|
break
|
}
|
} else {
|
if (This.$ghost.css('display') == 'none') {
|
This.$ghost.css({
|
display: 'block',
|
width: This.$areaData[id].width + 'px',
|
height: This.$areaData[id].height + 'px',
|
top:
|
This.$areaData[id].top +
|
t.top -
|
This.$workArea[0].parentNode.scrollTop +
|
'px',
|
left:
|
This.$areaData[id].left +
|
t.left -
|
This.$workArea[0].parentNode.scrollLeft +
|
'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 + 'px', top: Y + '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
|
var y = parseInt(p.style.top, 10) + 1
|
var t = getElCoordinateOveride(This.$workArea[0])
|
This.$textArea
|
.val(oldTxt)
|
.css({
|
display: 'block',
|
width: 120,
|
height: 26,
|
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('mouseup', 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
|
})
|
return false
|
})
|
// 绑定点击事件
|
this.$group.mouseup({ inthis: this }, function(e) {
|
var This = e.data.inthis
|
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 (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 'I': // 绑定变色功能
|
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)
|
var t = getElCoordinateOveride(this)
|
X = ev.x - t.left + this.parentNode.parentNode.scrollLeft
|
Y = ev.y - t.top + this.parentNode.parentNode.scrollTop
|
var color = ['red', 'yellow', 'blue', 'green']
|
e.data.inthis.addArea(new Date().getTime(), {
|
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
|
}
|
})
|
},
|
// 加入手动扩展编辑区功能,一次扩展200px
|
initExpendFunc: function() {
|
this.$workArea.append(
|
'<div class="Gooflow_extend_right"></div><div class="Gooflow_extend_bottom"></div>'
|
)
|
this.$workArea
|
.children('.Gooflow_extend_right')
|
.on('click', { inthis: this }, function(e) {
|
var This = e.data.inthis
|
var w = This.$workArea.width() + This.$workExtendStep
|
var h = This.$workArea.height()
|
This.$workArea.css({ width: w + 'px' })
|
if (GooFlow.prototype.useSVG == '') {
|
This.$draw.coordsize = w + ',' + h
|
}
|
This.$draw.style.width = w + 'px'
|
if (This.$group != null) {
|
This.$group.css({ width: w + 'px' })
|
}
|
var parentDiv = This.$workArea.parent()[0]
|
parentDiv.scrollLeft = parentDiv.scrollWidth
|
return false
|
})
|
this.$workArea
|
.children('.Gooflow_extend_bottom')
|
.on('click', { inthis: this }, function(e) {
|
var This = e.data.inthis
|
var w = This.$workArea.width()
|
var h = This.$workArea.height() + This.$workExtendStep
|
This.$workArea.css({ height: h + 'px' })
|
if (GooFlow.prototype.useSVG == '') {
|
This.$draw.coordsize = w + ',' + h
|
}
|
This.$draw.style.height = h + 'px'
|
if (This.$group != null) {
|
This.$group.css({ height: h + 'px' })
|
}
|
var parentDiv = This.$workArea.parent()[0]
|
parentDiv.scrollTop = parentDiv.scrollHeight
|
return false
|
})
|
},
|
// 初始化用来改变连线的连接端点的两个小方块的操作事件
|
initLinePointsChg: function() {
|
this.$mpFrom.on('mousedown', { inthis: this }, function(e) {
|
var This = e.data.inthis
|
This.switchToolBtn('cursor')
|
var ps = This.$mpFrom.data('p').split(',')
|
var pe = This.$mpTo.data('p').split(',')
|
$(this).hide()
|
This.$workArea
|
.data('lineEnd', {
|
x: pe[0],
|
y: pe[1],
|
id: This.$lineData[This.$lineOper.data('tid')].to
|
})
|
.css('cursor', 'crosshair')
|
var line = GooFlow.prototype.drawLine(
|
'GooFlow_tmp_line',
|
[ps[0], ps[1]],
|
[pe[0], pe[1]],
|
true,
|
true
|
)
|
This.$draw.appendChild(line)
|
return false
|
})
|
this.$mpTo.on('mousedown', { inthis: this }, function(e) {
|
var This = e.data.inthis
|
This.switchToolBtn('cursor')
|
var ps = This.$mpFrom.data('p').split(',')
|
var pe = This.$mpTo.data('p').split(',')
|
$(this).hide()
|
This.$workArea
|
.data('lineStart', {
|
x: ps[0],
|
y: ps[1],
|
id: This.$lineData[This.$lineOper.data('tid')].from
|
})
|
.css('cursor', 'crosshair')
|
var line = GooFlow.prototype.drawLine(
|
'GooFlow_tmp_line',
|
[ps[0], ps[1]],
|
[pe[0], pe[1]],
|
true,
|
true
|
)
|
This.$draw.appendChild(line)
|
return false
|
})
|
},
|
// 每一种类型结点及其按钮的说明文字
|
setNodeRemarks: function(remark) {
|
if (this.$tool == null) return
|
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', '')
|
} else if (this.$nowType == 'direct') {
|
this.blurItem()
|
}
|
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.marked ? ' item_mark' : ''
|
if (json.type.indexOf(' round') < 0) {
|
if (!json.width || json.width < 104) json.width = 104
|
if (!json.height || json.height < 26) json.height = 26
|
if (!json.top || json.top < 0) json.top = 0
|
if (!json.left || json.left < 0) json.left = 0
|
|
this.$nodeDom[id] = $(
|
"<div class='GooFlow_item" +
|
mark +
|
"' id='" +
|
id +
|
"' style='top:" +
|
json.top +
|
'px;left:' +
|
json.left +
|
"px'><table cellspacing='1' style='width:" +
|
(json.width - 2) +
|
'px;height:' +
|
(json.height - 2) +
|
"px;'><tr><td class='ico'><i class='ico_" +
|
json.type +
|
"'></i></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>"
|
)
|
} else {
|
json.width = 26
|
json.height = 26
|
this.$nodeDom[id] = $(
|
"<div class='GooFlow_item item_round" +
|
mark +
|
"' id='" +
|
id +
|
"' style='top:" +
|
json.top +
|
'px;left:' +
|
json.left +
|
"px'><table cellspacing='0'><tr><td class='ico'><i class='ico_" +
|
json.type +
|
"'></i></td></tr></table><div style='display:none'><div class='rs_close'></div></div><div class='span'>" +
|
json.name +
|
'</div></div>'
|
)
|
}
|
if (GooFlow.prototype.color.node) {
|
if (json.type.indexOf(' mix') > -1) {
|
this.$nodeDom[id].css({
|
'background-color': GooFlow.prototype.color.mix,
|
'border-color': GooFlow.prototype.color.mix
|
})
|
if (GooFlow.prototype.color.mixFont) {
|
this.$nodeDom[id]
|
.find('td:eq(1)')
|
.css('color', GooFlow.prototype.color.mixFont)
|
this.$nodeDom[id]
|
.find('.span')
|
.css('color', GooFlow.prototype.color.mixFont)
|
}
|
} else {
|
this.$nodeDom[id].css({
|
'background-color': GooFlow.prototype.color.node,
|
'border-color': GooFlow.prototype.color.node
|
})
|
}
|
if (mark && GooFlow.prototype.color.mark) {
|
this.$nodeDom[id].css({ 'border-color': GooFlow.prototype.color.mark })
|
}
|
}
|
if (json.type.indexOf(' mix') > -1) {
|
this.$nodeDom[id].addClass('item_mix')
|
}
|
|
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')
|
}
|
)
|
// 绑定用鼠标移动事件
|
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 ev = mousePosition(e)
|
var t = getElCoordinateOveride(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
|
var 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: This.$nodeData[id].width + 'px',
|
height: This.$nodeData[id].height + 'px',
|
top:
|
This.$nodeData[id].top +
|
t.top -
|
This.$workArea[0].parentNode.scrollTop +
|
'px',
|
left:
|
This.$nodeData[id].left +
|
t.left -
|
This.$workArea[0].parentNode.scrollLeft +
|
'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 + 'px', top: Y + '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' &&
|
!document.getElementById('GooFlow_tmp_line')
|
)
|
return
|
$(this)
|
.addClass('item_mark')
|
.addClass('crosshair')
|
.css('border-color', GooFlow.prototype.color.mark || '#ff8800')
|
}
|
)
|
this.$workArea.delegate(
|
'.GooFlow_item',
|
'mouseleave',
|
{ inthis: this },
|
function(e) {
|
if (
|
e.data.inthis.$nowType != 'direct' &&
|
!document.getElementById('GooFlow_tmp_line')
|
)
|
return
|
$(this)
|
.removeClass('item_mark')
|
.removeClass('crosshair')
|
if (this.id == e.data.inthis.$focus) {
|
$(this).css('border-color', GooFlow.prototype.color.line || '#3892D3')
|
} else {
|
$(this).css('border-color', GooFlow.prototype.color.node || '#A1DCEB')
|
}
|
}
|
)
|
// 绑定连线时确定初始点
|
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)
|
var 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' && !This.$mpTo.data('p')) return
|
var lineStart = This.$workArea.data('lineStart')
|
var lineEnd = This.$workArea.data('lineEnd')
|
if (lineStart && !This.$mpTo.data('p')) {
|
This.addLine(new Date().getTime(), {
|
from: lineStart.id,
|
to: this.id,
|
name: ''
|
})
|
This.$max++
|
} else {
|
if (lineStart) {
|
This.moveLinePoints(This.$focus, lineStart.id, this.id)
|
} else if (lineEnd) {
|
This.moveLinePoints(This.$focus, this.id, lineEnd.id)
|
}
|
if (!This.$nodeData[this.id].marked) {
|
$(this).removeClass('item_mark')
|
if (this.id != This.$focus) {
|
$(this).css('border-color', GooFlow.prototype.color.node)
|
} else {
|
$(this).css('border-color', GooFlow.prototype.color.line)
|
}
|
}
|
}
|
}
|
)
|
// 绑定双击编辑事件
|
this.$workArea.delegate(
|
'.GooFlow_item > .span',
|
'dblclick',
|
{ inthis: this },
|
function(e) {
|
var oldTxt = this.innerHTML
|
var This = e.data.inthis
|
var id = this.parentNode.id
|
var t = getElCoordinateOveride(This.$workArea[0])
|
This.$textArea
|
.val(oldTxt)
|
.css({
|
display: 'block',
|
height: $(this).height() + 6,
|
width: 100,
|
left:
|
t.left +
|
This.$nodeData[id].left -
|
This.$workArea[0].parentNode.scrollLeft -
|
26,
|
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 oldTxt = this.innerHTML
|
var This = e.data.inthis
|
var id = $(this)
|
.parents('.GooFlow_item')
|
.attr('id')
|
winDbClick(oldTxt, id)
|
/* var t = getElCoordinateOveride(This.$workArea[0])
|
|
This.$textArea
|
.val(oldTxt)
|
.css({
|
display: 'block',
|
width: $(this).width() + 26,
|
height: $(this).height() + 6,
|
left:
|
t.left +
|
26 +
|
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 ev = mousePosition(e)
|
var t = getElCoordinateOveride(This.$workArea[0])
|
This.$ghost.css({
|
display: 'block',
|
width: This.$nodeData[id].width + 'px',
|
height: This.$nodeData[id].height + 'px',
|
top:
|
This.$nodeData[id].top +
|
t.top -
|
This.$workArea[0].parentNode.scrollTop +
|
'px',
|
left:
|
This.$nodeData[id].left +
|
t.left -
|
This.$workArea[0].parentNode.scrollLeft +
|
'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 < 104) X = 104
|
if (Y < 26) Y = 26
|
isMove = true
|
switch (cursor) {
|
case 'nw-resize':
|
This.$ghost.css({ width: X + 'px', height: Y + 'px' })
|
break
|
case 'w-resize':
|
This.$ghost.css({ width: X + 'px' })
|
break
|
case 'n-resize':
|
This.$ghost.css({ height: Y + 'px' })
|
break
|
}
|
}
|
document.onmouseup = function(e) {
|
document.onmousemove = null
|
document.onmouseup = null
|
This.$ghost.hide()
|
if (!isMove) return
|
if (!e) e = window.event
|
This.resizeNode(
|
id,
|
This.$ghost.outerWidth(),
|
This.$ghost.outerHeight()
|
)
|
}
|
}
|
)
|
},
|
// 获取结点/连线/分组区域的详细信息
|
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(this.$focus, 'node'))
|
return false
|
jq.removeClass('item_focus')
|
.children('div:eq(0)')
|
.css('display', 'none')
|
if (this.$nodeData[this.$focus].marked) {
|
jq.addClass('item_mark').css(
|
'border-color',
|
GooFlow.prototype.color.mark || '#ff8800'
|
)
|
}
|
} else {
|
if (this.onItemBlur != null && !this.onItemBlur(this.$focus, 'line'))
|
return false
|
if (GooFlow.prototype.useSVG != '') {
|
if (!this.$lineData[this.$focus].marked) {
|
jq[0].childNodes[1].setAttribute(
|
'stroke',
|
GooFlow.prototype.color.line || '#3892D3'
|
)
|
jq[0].childNodes[1].setAttribute('marker-end', 'url(#arrow1)')
|
}
|
} else {
|
if (!this.$lineData[this.$focus].marked) {
|
jq[0].strokeColor = GooFlow.prototype.color.line || '#3892D3'
|
}
|
}
|
this.$lineMove
|
.hide()
|
.removeData('type')
|
.removeData('tid')
|
if (this.$editable) {
|
this.$lineOper.hide().removeData('tid')
|
this.$mpFrom.hide().removeData('p')
|
this.$mpTo.hide().removeData('p')
|
}
|
}
|
}
|
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 (GooFlow.prototype.color.line) {
|
jq.css('border-color', GooFlow.prototype.color.line)
|
}
|
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',
|
GooFlow.prototype.color.mark || '#ff8800'
|
)
|
jq[0].childNodes[1].setAttribute('marker-end', 'url(#arrow2)')
|
} else {
|
jq[0].strokeColor = GooFlow.prototype.color.mark || '#ff8800'
|
}
|
if (!this.$editable) return
|
var x, y, from, to, n
|
if (GooFlow.prototype.useSVG != '') {
|
from = jq.attr('from').split(',')
|
to = jq.attr('to').split(',')
|
n = [from[0], from[1], to[0], to[1]]
|
} else {
|
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=getElCoordinateOveride(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 - 40
|
y = (from[1] + to[1]) / 2 + 4
|
this.$lineOper
|
.css({ display: 'block', left: x + 'px', top: y + 'px' })
|
.data('tid', id)
|
if (this.$editable) {
|
this.$mpFrom
|
.css({
|
display: 'block',
|
left: n[0] - 4 + 'px',
|
top: n[1] - 4 + 'px'
|
})
|
.data('p', n[0] + ',' + n[1])
|
this.$mpTo
|
.css({
|
display: 'block',
|
left: n[2] - 4 + 'px',
|
top: n[3] - 4 + 'px'
|
})
|
.data('p', n[2] + ',' + n[3])
|
}
|
this.$draw.appendChild(jq[0])
|
}
|
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) {
|
var oldName
|
if (type == 'node') {
|
// 如果是结点
|
if (!this.$nodeData[id]) return
|
if (this.$nodeData[id].name == name) return
|
if (this.onItemRename != null && !this.onItemRename(id, name, 'node'))
|
return
|
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 width = this.$nodeDom[id].width()
|
var height = this.$nodeDom[id].height()
|
this.$nodeDom[id]
|
.children('table')
|
.css({ width: width + 'px', height: height + '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') {
|
// 如果是线
|
if (!this.$lineData[id]) return
|
if (this.$lineData[id].name == name) return
|
if (this.onItemRename != null && !this.onItemRename(id, name, 'line'))
|
return
|
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)
|
}
|
|
this.$nodeDom[id]
|
.children('table')
|
.css({ width: width - 2 + 'px', height: height - 2 + 'px' })
|
// width=this.$nodeDom[id].outerWidth();
|
// 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])
|
},
|
// 删除结点
|
delNode: function(id, trigger) {
|
if (!this.$nodeData[id]) return
|
if (
|
trigger != false &&
|
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, false)
|
}
|
}
|
// 再删除结点本身
|
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) {
|
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(i, data.nodes[i])
|
for (var j in data.lines) this.addLine(j, data.lines[j])
|
for (var k in data.areas) this.addArea(k, data.areas[k])
|
this.$editable = t
|
this.$deletedItem = {}
|
// 自行重构工作区,使之大小自适应
|
var width = this.$workArea.width()
|
var height = this.$workArea.height()
|
var maxW = 0
|
var maxH = 0
|
for (var key in this.$nodeData) {
|
var item = this.$nodeData[key]
|
if (maxW < item.width + item.left) {
|
maxW = item.width + item.left
|
}
|
if (maxH < item.height + item.top) {
|
maxH = item.height + item.top
|
}
|
}
|
for (var key in this.$areaData) {
|
var item = this.$areaData[key]
|
if (maxW < item.width + item.left) {
|
maxW = item.width + item.left
|
}
|
if (maxH < item.height + item.top) {
|
maxH = item.height + item.top
|
}
|
}
|
for (var key in this.$lineData) {
|
var item = this.$lineData[key]
|
if (item.M && item.type == 'lt' && maxW < item.M) {
|
maxW = M + 4
|
}
|
if (item.M && item.type == 'tb' && maxH < item.M) {
|
maxH = M + 4
|
}
|
}
|
while (maxW > width) {
|
width += this.$workExtendStep
|
}
|
while (maxH > height) {
|
height += this.$workExtendStep
|
}
|
this.$workArea.css({ height: height + 'px', width: width + 'px' })
|
if (GooFlow.prototype.useSVG == '') {
|
this.$draw.coordsize = width + ',' + height
|
}
|
this.$draw.style.width = width + 'px'
|
this.$draw.style.height = +height + 'px'
|
if (this.$group != null) {
|
this.$group.css({ height: height + 'px', width: width + 'px' })
|
}
|
},
|
// 用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
|
}
|
for (var k1 in ret.nodes) {
|
if (!ret.nodes[k1].marked) {
|
delete ret.nodes[k1].marked
|
}
|
}
|
for (var k2 in ret.lines) {
|
if (!ret.lines[k2].marked) {
|
delete ret.lines[k2].marked
|
}
|
}
|
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
|
tmp = this.$nodeDom[oldId].attr('id', newId)
|
delete this.$nodeDom[oldId]
|
this.$nodeDom[newId] = tmp
|
}
|
break
|
case 'line':
|
if (this.$lineData[oldId]) {
|
tmp = this.$lineData[oldId]
|
delete this.$lineData[oldId]
|
this.$lineData[newId] = tmp
|
tmp = this.$lineDom[oldId].attr('id', newId)
|
delete this.$lineDom[oldId]
|
this.$lineDom[newId] = tmp
|
}
|
break
|
case 'area':
|
if (this.$areaData[oldId]) {
|
tmp = this.$areaData[oldId]
|
delete this.$areaData[oldId]
|
this.$areaData[newId] = tmp
|
tmp = this.$areaDom[oldId].attr('id', newId)
|
delete this.$areaDom[oldId]
|
this.$areaDom[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', mark ? 2.4 : 1.4)
|
path.setAttribute('stroke-linecap', 'round')
|
path.setAttribute('fill', 'none')
|
if (dash) path.setAttribute('style', 'stroke-dasharray:6,5')
|
if (mark) {
|
path.setAttribute('stroke', GooFlow.prototype.color.mark || '#ff8800')
|
path.setAttribute('marker-end', 'url(#arrow2)')
|
} else {
|
path.setAttribute('stroke', GooFlow.prototype.color.line || '#3892D3')
|
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.setAttribute('fill', GooFlow.prototype.color.lineFont || '#333')
|
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)
|
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 = GooFlow.prototype.color.mark || '#ff8800'
|
else line.strokeColor = GooFlow.prototype.color.line || '#3892D3'
|
line.fillColor = GooFlow.prototype.color.line || '#3892D3'
|
}
|
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', mark ? 2.4 : 1.4)
|
path.setAttribute('stroke-linecap', 'round')
|
path.setAttribute('fill', 'none')
|
if (mark) {
|
path.setAttribute('stroke', GooFlow.prototype.color.mark || '#ff8800')
|
path.setAttribute('marker-end', 'url(#arrow2)')
|
} else {
|
path.setAttribute('stroke', GooFlow.prototype.color.line || '#3892D3')
|
path.setAttribute('marker-end', 'url(#arrow1)')
|
}
|
poly.appendChild(hi)
|
poly.appendChild(path)
|
var text = document.createElementNS('http://www.w3.org/2000/svg', 'text')
|
text.setAttribute('fill', GooFlow.prototype.color.lineFont || '#333')
|
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)
|
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 = mark ? '2.4' : '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 = GooFlow.prototype.color.mark || '#ff8800'
|
else poly.strokeColor = GooFlow.prototype.color.line || '#3892D3'
|
}
|
return poly
|
},
|
// 计算两个结点间要连直线的话,连线的开始坐标和结束坐标
|
calcStartEnd: function(n1, n2) {
|
var X_1, Y_1, X_2, Y_2
|
// X判断:
|
var x11 = n1.left
|
var x12 = n1.left + n1.width
|
var x21 = n2.left
|
var 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
|
var y12 = n1.top + n1.height
|
var y21 = n2.top
|
var 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 = []
|
var m1 = []
|
var m2 = []
|
var 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
|
}
|
},
|
// 原lineData已经设定好的情况下,只在绘图工作区画一条线的页面元素
|
addLineDom: function(id, lineData) {
|
var n1 = this.$nodeData[lineData.from]
|
var n2 = this.$nodeData[lineData.to] // 获取开始/结束结点的数据
|
if (!n1 || !n2) return
|
// 开始计算线端点坐标
|
var res
|
if (lineData.type && lineData.type != 'sl')
|
res = GooFlow.prototype.calcPolyPoints(n1, n2, lineData.type, lineData.M)
|
else res = GooFlow.prototype.calcStartEnd(n1, n2)
|
if (!res) return
|
|
if (lineData.type == 'sl')
|
this.$lineDom[id] = GooFlow.prototype.drawLine(
|
id,
|
res.start,
|
res.end,
|
lineData.marked
|
)
|
else
|
this.$lineDom[id] = GooFlow.prototype.drawPoly(
|
id,
|
res.start,
|
res.m1,
|
res.m2,
|
res.end,
|
lineData.marked
|
)
|
this.$draw.appendChild(this.$lineDom[id])
|
if (GooFlow.prototype.useSVG == '') {
|
this.$lineDom[id].childNodes[1].innerHTML = lineData.name
|
if (lineData.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 = lineData.name
|
},
|
// 增加一条线
|
addLine: function(id, json) {
|
if (this.onItemAdd != null && !this.onItemAdd(id, 'line', json)) return
|
if (this.$undoStack && this.$editable) {
|
this.pushOper('delLine', [id])
|
}
|
if (json.from == json.to) return
|
var n1 = this.$nodeData[json.from]
|
var n2 = this.$nodeData[json.to] // 获取开始/结束结点的数据
|
if (!n1 || !n2) return
|
// 避免两个节点间不能有一条以上同向接连线
|
for (var k in this.$lineData) {
|
if (
|
json.from == this.$lineData[k].from &&
|
json.to == this.$lineData[k].to
|
)
|
return
|
}
|
// 设置$lineData[id]
|
this.$lineData[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.marked) this.$lineData[id].marked = json.marked
|
else this.$lineData[id].marked = false
|
// 设置$lineData[id]完毕
|
|
this.addLineDom(id, this.$lineData[id])
|
|
++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, M) {
|
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.$lineData[id].M]
|
this.pushOper('setLineType', paras)
|
}
|
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
|
)
|
if (M) {
|
this.setLineM(id, M, true)
|
} else {
|
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.$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.$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, trigger) {
|
if (!this.$lineData[id]) return
|
if (
|
trigger != false &&
|
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.$mpFrom.hide().removeData('p')
|
this.$mpTo.hide().removeData('p')
|
}
|
if (this.$lineOper) {
|
this.$lineOper.hide().removeData('tid')
|
}
|
},
|
// 变更连线两个端点所连的结点
|
// 参数:要变更端点的连线ID,新的开始结点ID、新的结束结点ID;如果开始/结束结点ID是传入null或者"",则表示原端点不变
|
moveLinePoints: function(lineId, newStart, newEnd, noStack) {
|
if (newStart == newEnd) return
|
if (!lineId || !this.$lineData[lineId]) return
|
if (newStart == null || newStart == '')
|
newStart = this.$lineData[lineId].from
|
if (newEnd == null || newEnd == '') newEnd = this.$lineData[lineId].to
|
|
// 避免两个节点间不能有一条以上同向接连线
|
for (var k in this.$lineData) {
|
if (newStart == this.$lineData[k].from && newEnd == this.$lineData[k].to)
|
return
|
}
|
if (
|
this.onLinePointMove != null &&
|
!this.onLinePointMove(id, newStart, newEnd)
|
)
|
return
|
if (this.$undoStack && !noStack) {
|
var paras = [
|
lineId,
|
this.$lineData[lineId].from,
|
this.$lineData[lineId].to
|
]
|
this.pushOper('moveLinePoints', paras)
|
}
|
if (newStart != null && newStart != '') {
|
this.$lineData[lineId].from = newStart
|
}
|
if (newEnd != null && newEnd != '') {
|
this.$lineData[lineId].to = newEnd
|
}
|
// 重建转换线
|
this.$draw.removeChild(this.$lineDom[lineId])
|
this.addLineDom(lineId, this.$lineData[lineId])
|
if (this.$editable) {
|
this.$lineData[lineId].alt = true
|
}
|
},
|
|
// 用颜色标注/取消标注一个结点或转换线,常用于显示重点或流程的进度。
|
// 这是一个在编辑模式中无用,但是在纯浏览模式中非常有用的方法,实际运用中可用于跟踪流程的进度。
|
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')
|
.css('border-color', GooFlow.prototype.color.mark)
|
} else {
|
this.$nodeDom[id].removeClass('item_mark')
|
if (id != this.$focus)
|
this.$nodeDom[id].css('border-color', 'transparent')
|
}
|
} 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.$lineDom[id].childNodes[1].setAttribute(
|
'stroke',
|
GooFlow.prototype.color.mark || '#ff8800'
|
)
|
this.$lineDom[id].childNodes[1].setAttribute(
|
'marker-end',
|
'url(#arrow2)'
|
)
|
this.$lineDom[id].childNodes[1].setAttribute('stroke-width', 2.4)
|
} else {
|
this.$lineDom[id].childNodes[1].setAttribute(
|
'stroke',
|
GooFlow.prototype.color.line || '#3892D3'
|
)
|
this.$lineDom[id].childNodes[1].setAttribute(
|
'marker-end',
|
'url(#arrow1)'
|
)
|
this.$lineDom[id].childNodes[1].setAttribute('stroke-width', 1.4)
|
}
|
} else {
|
if (mark) {
|
this.$lineDom[id].strokeColor =
|
GooFlow.prototype.color.mark || '#ff8800'
|
this.$lineDom[id].strokeWeight = '2.4'
|
} else {
|
this.$lineDom[id].strokeColor =
|
GooFlow.prototype.color.line || '#3892D3'
|
this.$lineDom[id].strokeWeight = '1.2'
|
}
|
}
|
}
|
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, trigger) {
|
if (!this.$areaData[id]) return
|
if (this.$undoStack) {
|
var paras = [id, this.$areaData[id]]
|
this.pushOper('addArea', paras)
|
}
|
if (
|
trigger != false &&
|
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)
|
}
|
|
this.$areaDom[id]
|
.children('.bg')
|
.css({ width: width + 'px', height: height + 'px' })
|
// width=this.$areaDom[id].outerWidth();
|
// height=this.$areaDom[id].outerHeight();
|
// this.$areaDom[id].children("bg").css({width:width+"px",height:height+"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 +
|
'px;height:' +
|
json.height +
|
"px'></div>" +
|
'<label>' +
|
json.name +
|
"</label><i></i><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
|
var h = height || 500
|
this.$bgDiv.css({ height: h + 'px', width: w + 'px' })
|
var headHeight = 0
|
var hack = 8
|
if (this.$head != null) {
|
headHeight = 26
|
hack = 5
|
}
|
if (this.$tool != null) {
|
this.$tool.css({ height: h - headHeight - hack + 'px' })
|
w -= 31
|
}
|
w -= 9
|
h = h - headHeight - (this.$head != null ? 5 : 8)
|
this.$workArea.parent().css({ height: h + 'px', width: w + 'px' })
|
|
if (this.$workArea.width() > w) {
|
w = this.$workArea.width()
|
}
|
if (this.$workArea.height() > h) {
|
h = this.$workArea.height()
|
}
|
|
this.$workArea.css({ height: h + 'px', width: w + 'px' })
|
if (GooFlow.prototype.useSVG == '') {
|
this.$draw.coordsize = w + ',' + h
|
}
|
this.$draw.style.width = w + 'px'
|
this.$draw.style.height = +h + 'px'
|
if (this.$group != null) {
|
this.$group.css({ height: h + 'px', width: w + 'px' })
|
}
|
}
|
}
|
GooFlow.prototype.color = {}
|
// 将此类的构造函数加入至JQUERY对象中
|
jQuery.extend({
|
createGooFlow: function(bgDiv, property) {
|
return new GooFlow(bgDiv, property)
|
}
|
})
|