web 流程编辑器

自己写这个流程编辑器的原因

1:有些人弄了个流程编辑器出来,看了一下还不错,但是,不给源码,不知道有什么技术难题,有什么值得保密的。

 

         2:还有写人理论讲了一大堆也没看出弄出个什么东西出来。

 

本人用了2天空有时间,基于jQuery,与Raphel 做了一个流程编辑器。

 

操作习惯类似与PowerBuilder。

 

附件是工程代码,可以随意使用,呵呵。

 

 

主要的业务代码webFlow.js

 

/*
 * 记录工具面板中被选中的工具
 * pointer:指针,用来选择、移动画出的图形
 *
 * line:划线
 *
 *
 */
var g_selected = "pointer";

//恢复操作栈
var g_redoStack = [];

/*
 *
 * 节点信息
 * 	{node: [],il: [],ol: [],nodeType: nodeType}
 *
 */
var g_nodes = [];

/*
 * 线条信息
 * {lineId,bNodeId,eNodeId}
 *
 */
var g_lines = [];

//线的起点坐标
var g_lsp = {
    x: 0,
    y: 0
};
//线的开始节点标识
var g_lsNodeId = 0;
var g_preLine;


//当前移动节点标识
var g_moveNodeId = 0;

var g_mskNodeSet = [];




var g_cr = 15, g_sw = 100, g_sh = 60, g_sr = 10, g_mskNodeObj;
var g_ndsMask = {
    "stroke-dasharray": "- .",
    "fill-opacity": 0,
    stroke: "black",
    "stroke-width": 5,
    fill: "white"
}


//删除草图
function rmPreDoodle(e){
    switch (g_selected) {
        case "pointer":
            _pointerRMDHandler(e);
            break;
        case "line":
            _lineRMDHandler(e);
            break;
    }
    
}


//节点样式对象
var g_ndsSelected = {
    "stroke-dasharray": "- .",
    "fill-opacity": 1,
    stroke: "black",
    "stroke-width": 5
}
var g_ndsNormal = {
    "stroke-dasharray": "",
    "stroke-width": 1,
    fill: "#4674a8",
    "stroke-opacity": .3,
    "fill-opacity": .7,
    stroke: ""
}

var g_ndsHide = {
    "stroke-dasharray": "",
    "stroke-width": 1,
    fill: "#4674a8",
    "stroke-opacity": 0,
    "fill-opacity": 0,
    stroke: ""
}

function _pointerRMDHandler(e){


}

function _lineRMDHandler(e){
    if (g_preLine) 
        g_preLine.remove();
}


//-----------------------------------------------MOUSEMOVE----------------------------------------------------

function mouseMovehandler(e){
    switch (g_selected) {
        case "pointer":
            _pointerMMHandler(e);
            break;
        case "line":
            _lineMMHandler(e);
            break;
        case "segment":
            break;
    }
    
}


function _pointerMMHandler(e){
    if (!g_moveNodeId) 
        return;
    
}

var udFlag, g_pY = 0;

function _lineMMHandler(e){
    //没有点击节点不划线
    if (g_lsNodeId == 0) 
        return;
    var r = e.data.r;
    rmPreDoodle(e);
    var x2 = e.pageX, y2 = e.pageY;
    udFlag = y2 > g_pY ? -1 : 1;
    
    g_preLine = r.ai.line(g_lsp.x, g_lsp.y, x2 + udFlag * 20, y2 + udFlag * 20).attr({
        stroke: "gray",
        "stroke-dasharray": "- ",
		"stroke-width":2
    });
    g_pY = y2;
    
    
}



//-----------------------------------------------MOUSECLICK----------------------------------------------------

function mouseClickhandler(e){
    switch (g_selected) {
        case "pointer":
            _pointerMCHandler(e);
            break;
        case "line":
            break;
        case "segment":
            crtNode("segment", e.data.r, e);
            break;
        case "condition":
            crtNode("condition", e.data.r, e);
            break;
		case "synchro":
            crtNode("synchro", e.data.r, e);
            break;
    }
    
}

function _pointerMCHandler(e){

}


//---------------------------------------------鼠标右键处理----------------------------------------------------
function contextmenuHandler(e){
    e.preventDefault();
    rmPreDoodle(e);
    g_lsNodeId = 0;
    top.initPaletee(false);
}

//------------------------------------------创建节点-----------------------------------------------------------

function _crtCondition(x, y, r){
    return r.path(["M", x + g_sw / 2, y, "L", x + g_sw, y + g_sh / 2, x + g_sw / 2, y + g_sh, x, y + g_sh / 2, "z"]).attr(g_ndsNormal).toBack();
}

function _crtSynchro(x, y, r){
	var p=["M",x,y,"L",x+g_sw,y,x+g_sw,y+g_sh,x,y+g_sh,x,y,"M",x,y+g_sh/2,"L",x+g_sw,y+g_sh/2]
	var t=["M",x+g_sw/4,y,"L",x+g_sw/4,y+g_sh/2,x+g_sw/4-5,y+g_sh/2-5,"M",x+g_sw/4,y+g_sh/2,"L",x+g_sw/4+5,y+g_sh/2-5,"M",x+g_sw*3/4,y,"L",x+g_sw*3/4,y+g_sh/2,x+g_sw*3/4-5,y+g_sh/2-5,"M",x+g_sw*3/4,y+g_sh/2,"L",x+g_sw/4+5,y+g_sh/2-5,"M",x+g_sw/2,y+g_sh/2,"L",x+g_sw/2,y+g_sh,x+g_sw/2-5,y+g_sh-5,"M",x+g_sw/2,y+g_sh,"L",x+g_sw/2+5,y+g_sh/-5]

	return r.path(p.concat(t)).toBack();
}

function crtNode(nodeType, r, e, nodeName, fillColor){
    var nodeId = new Date().getTime(), c;
    var x = e.pageX - g_sw / 2;
    var y = e.pageY - g_sh / 2;
    var ndStyle = g_ndsNormal;
    switch (nodeType) {
        case "beginNode":
        case "endNode":
            ndStyle = g_ndsHide;
            c = r.circle(x + g_sw / 2, y + g_sh / 2, g_sw / 2 - 15).attr(g_ndsNormal);
            break;
        case "condition":
            ndStyle = g_ndsHide;
            c = _crtCondition(x, y, r);
            break;
		case "synchro":
            ndStyle = g_ndsHide;
            c = _crtSynchro(x, y, r);
            break;
    }
    
    var nd = r.rect(x, y, g_sw, g_sh, g_sr).attr(ndStyle).toFront();
    if (fillColor) 
        nd.attr("fill", fillColor);
    
    
    var _nodeName = nodeName ? nodeName : "节点名称";
    var txt = r.text(e.pageX, e.pageY, _nodeName);
    
    g_nodes[nodeId] = {
        node: [nd, txt, c],
        il: [],
        ol: [],
        fillCollr: fillColor,
        nodeType: nodeType
    };
    
    _addNodeHandler(nd, nodeId, r);
    
}


//----------------------------------------------------节点事件处理函数--------------------------------------------

function _addNodeHandler(nd, nodeId, r){
    $(nd.node).bind("mouseout", {
        nodeId: nodeId,
        r: r
    }, _ndMOHandler);
    $(nd.node).bind("mouseover", {
        nodeId: nodeId,
        r: r
    }, _ndMIHandler);
    $(nd.node).bind("click", {
        nodeId: nodeId,
        r: r
    }, _ndMCHandler);
    $(nd.node).bind("dblclick", {
        nodeId: nodeId,
        r: r
    }, _ndMDCHandler);
    
    $(nd.node).bind("mousemove", {
        nodeId: nodeId,
        r: r
    }, _ndMMCHandler);
    
}

function showInfo(msg){
    alert(msg);
}

function _ndMOHandler(e){
    var nodeId = e.data.nodeId;
    var no = g_nodes[nodeId];
    switch (no.nodeType) {
        case "beginNode":
        case "endNode":
        case "condition":
		case "synchro":
            no.node[2].attr(g_ndsNormal);
            break;
        default:
            no.node[0].attr(g_ndsNormal);
    }
}

function _ndMIHandler(e){

    var nodeId = e.data.nodeId;
    
    var no = g_nodes[nodeId];
    switch (no.nodeType) {
        case "beginNode":
        case "endNode":
        case "condition":
		case "synchro":
            no.node[2].attr(g_ndsSelected);
            break;
        default:
            no.node[0].attr(g_ndsSelected);
    }
}

//节点被点击处理时间
function _ndMCHandler(e){

    switch (g_selected) {
        case "line":
            _ndClickForLine(e);
            break;
        case "pointer":
            _ndClickForMove(e);
            break;
    }
    
    e.stopPropagation();
}

function _lineAsBeginNode(e){
    var nodeId = e.data.nodeId;
    var no = g_nodes[nodeId];
    var node = no.node[0];
    switch (no.nodeType) {
        case "beginNode":
            if (no.ol.length > 0) {
                showInfo("开始节点只可以有一个输出路径");
                return;
            }
		case "condition":
		case "synchro":
        case "segment":
            g_lsNodeId = nodeId;
            g_lsp.x = node.attr("x") + g_sw / 2;
            g_lsp.y = node.attr("y") + g_sh / 2;
            break;
        case "endNode":
            break;
    }
}

function _lineAsEndNode(e){
    rmPreDoodle();
    var r = e.data.r, leNodeId = e.data.nodeId;
    
    //不可以对自己划线
    if (!leNodeId || leNodeId == g_lsNodeId || g_lsNodeId == 0 || g_nodes[leNodeId].nodeType == "beginNode") 
        return;
    var xy = _getLineEndXY(leNodeId);
    var line = r.ai.lineWithArrow(g_lsp.x, g_lsp.y, xy.x, xy.y).attr({
        stroke: "#f88817","stroke-width":2
    });
    
    //记录线条信息
    var lineId = new Date().getTime();
    g_lines[lineId] = {
        lineId: lineId,
        bNodeId: g_lsNodeId,
        eNodeId: leNodeId,
        line: line
    };
    
    //修改线条端点对应节点属性
    g_nodes[g_lsNodeId].ol.push(lineId);
    g_nodes[leNodeId].il.push(lineId);
    
    g_lsNodeId = 0;
    
}

//点击节点来划线
function _ndClickForLine(e){
    if (g_lsNodeId) 
        _lineAsEndNode(e);
    else 
        _lineAsBeginNode(e);
}

//点击节点来移动节点
function _ndClickForMove(e){
    var no = g_nodes[e.data.nodeId];
    no.bMoved = !no.bMoved;
}


function _ndMDCHandler(e){

    e.stopPropagation();
}

function _ndMMCHandler(e){

    if (g_selected != "pointer") 
        return;
    
    var nodeId = e.data.nodeId;
    var no = g_nodes[nodeId]
    
    if (!no.bMoved) 
        return;
    
    g_moveNodeId = nodeId;
    
    _getMskNode(no.nodeType, e);
    
    e.stopPropagation();
    
}


function crtMskNode(r){
    g_mskNodeSet = r.set();
    g_mskNodeSet.push(r.rect(100, 100, g_sw, g_sh, g_sr).hide());
    $(g_mskNodeSet[0].node).bind("click", {
        r: r
    }, _mskNodeClickHandler).bind("mousemove", {
        r: r
    }, _mskNodeMoveHandler);
    g_mskNodeSet.attr(g_ndsMask);
}


function _getMskNode(nodeType, e){

    switch (nodeType) {
        case "beginNode":
        case "endNode":
        case "segment":
        case "condition":
		case "synchro":
            g_mskNodeObj = g_mskNodeSet[0];
            break;
    }
    
    if (!g_mskNodeObj) 
        return;
    
    g_mskNodeObj.show();
    
    _moveNode(g_mskNodeObj, e);
}

function _mskNodeClickHandler(e){
    g_mskNodeObj.hide();
    //移动原始对象
    var no = g_nodes[g_moveNodeId];
    no.bMoved = false;
    
    _moveNode(no.node[0], e, g_moveNodeId);
    
    g_mskNodeObj = 0;
    g_moveNodeId = 0;
}

function _mskNodeMoveHandler(e){
    _moveNode(g_mskNodeObj, e);
}

function _moveNode(node, e, realNodeId){
    node.attr({
        x: e.pageX - g_sw / 2,
        y: e.pageY - g_sh / 2
    })
    
    if (!realNodeId) 
        return;
    
    //移动文字
    var no = g_nodes[realNodeId];
    var node = no.node[0], txt = no.node[1], p = no.node[2];
    var x = node.attr("x"), y = node.attr("y");
    
    switch (no.nodeType) {
        case "beginNode":
        case "endNode":
            p.attr({
                cx: x + g_sw / 2,
                cy: y + g_sh / 2
            });
            break;
        case "condition":
            p.remove();
            p = _crtCondition(x, y, e.data.r);
            no.node[2] = p;
            break;
		case "synchro":
			p.remove();
            p = _crtSynchro(x, y, e.data.r);
            no.node[2] = p;
        case "segment":
            
            break;
    }
    
    txt.attr({
        x: x + g_sw / 2,
        y: y + g_sh / 2
    });
    //移动线条
    
    _moveRltLine(realNodeId, no.il, no.ol, x, y);
}

function _moveRltLine(nodeId, il, ol, x, y){
    var oL = {}, line, bNode;
    //移动输出直线
    for (var i = 0, ii = ol.length; i < ii; i++) {
        oL = g_lines[ol[i]];
        
        //删除原有的线
        oL.line.remove();
        
        g_lsNodeId = nodeId;
        g_lsp.x = x + g_sw / 2;
        g_lsp.y = y + g_sh / 2;
        
        var xy = _getLineEndXY(oL.eNodeId);
        line = r.ai.lineWithArrow(g_lsp.x, g_lsp.y, xy.x, xy.y).attr({
            stroke: "#f88817","stroke-width":2
        });
        oL.line = line;
        g_lsNodeId = 0;
    }
    
    //移动输入直线
    
    for (var i = 0, ii = il.length; i < ii; i++) {
        oL = g_lines[il[i]];
        
        //删除原有的线
        oL.line.remove();
        
        g_lsNodeId = oL.bNodeId;
        bNode = g_nodes[g_lsNodeId].node[0];
        g_lsp.x = bNode.attr("x") + g_sw / 2;
        g_lsp.y = bNode.attr("y") + g_sh / 2;
        
        var xy = _getLineEndXY(nodeId);
        line = r.ai.lineWithArrow(g_lsp.x, g_lsp.y, xy.x, xy.y).attr({
            stroke: "#f88817","stroke-width":2
        });
        
        oL.line = line;
        g_lsNodeId = 0;
    }
    
}

/*
 * 返回点一相对于点二的位置 关系
 *
 */
function g_getPointsRlt(x1, y1, x2, y2, w, h){

    var s = (y1 < y2 && x1 < x2) ? [0, 0] : ((y1 < y2 && x1 > x2 && x1 < x2 + w) ? [0.5, 0] : ((y1 < y2 && x1 > x2 + w) ? [1, 0] : ((y1 > y2 + h && x1 < x2) ? [0, 1] : ((y1 > y2 + h && x1 > x2 && x1 < x2 + w) ? [0.5, 1] : ((y1 > y2 + h && x1 > x2 + w) ? [1, 1] : ((x1 < x2) ? [0, 0.5] : [1, 0.5]))))));
    
    return s;
}



//获取路径的终点坐标
function _getLineEndXY(nodeId){
    var xy = {};
    xy.x = 0;
    xy.y = 0;
    var no = g_nodes[nodeId].node[0];
    
    var cx = no.attr("cx"), cy = no.attr("cy"), cr = no.attr("r"), x = no.attr("x"), y = no.attr("y");
    var lType = [], w = g_sw, h = g_sh;
    switch (g_nodes[nodeId].nodeType) {
        case "endNode":
        case "segment":
		case "condition":
		case "synchro":
            lType = g_getPointsRlt(g_lsp.x, g_lsp.y, x, y, g_sw, g_sh);
            break;
    }
    //调整结束点坐标
    xy.x = x + lType[0] * w;
    xy.y = y + lType[1] * h;
    
    
    //调整开始节点坐标
    
    var bsnX = g_lsp.x - w / 2;
    g_lsp.x = g_lsp.x + w / 2 - lType[0] * w;
    g_lsp.y = g_lsp.y + h / 2 - lType[1] * h;
    
    //调整开始点x
    g_lsp.x = (xy.x > bsnX && xy.x < bsnX + w) ? xy.x : g_lsp.x;
    
    //调整结束点y
    xy.y = (g_lsp.y > y && g_lsp.y < y + h) ? g_lsp.y : xy.y;
    
    return xy;
}

 

 

你可能感兴趣的:(Web,PowerBuilder,jQuery,ViewUI)