`
movenut
  • 浏览: 127862 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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;
}

 

 

分享到:
评论

相关推荐

    Activiti工作流整合Web流程设计器整合

    Web流程设计器是用于创建和编辑流程图的Web应用程序,它通常提供图形化的用户界面,让用户无需编写代码就能绘制流程图。在Activiti中,常用的Web流程设计器有Alfresco Share、Activiti Modeler或BPMN 2.0兼容的第三...

    web在线编辑器_js在线运行_webJS编辑器_js在线运行_web在线编辑器_在线web编辑_

    总的来说,Web在线编辑器是现代前端开发的重要工具,它们简化了开发流程,增强了协作效率,同时也降低了技术门槛,使得更多人能参与到网页制作中来。随着技术的不断发展,这类工具的功能将更加完善,为开发者带来更...

    工作流流程编辑器(含全部源码)

    工作流流程编辑器是一款用于设计和管理业务流程的工具,它包含了全部的源代码,使得开发者可以深入理解其内部机制并进行定制化开发。在IT领域,工作流(Workflow)是一种自动化处理业务流程的技术,它将业务过程中的...

    简单方便的web打印编辑器

    这种编辑器设计的目标可能是为了简化用户的工作流程,使得在Web环境中进行文字处理变得更加高效。通常,它们会提供基础的文字格式调整选项,如字体、字号、颜色、对齐方式等,以及插入图片、链接等富文本功能。同时...

    经典在线web编辑器

    综上所述,经典在线Web编辑器是现代Web开发中不可或缺的一部分,它们简化了文档处理流程,提升了用户体验。通过自定义控件的高度和利用开源编辑器如CKEditor,开发者能够创建出符合自身需求的高效在线编辑环境。理解...

    一个Web编辑器

    总的来说,Web编辑器是Web应用中不可或缺的一部分,它简化了用户的内容创作流程,提高了用户在网页上的互动体验。通过理解其内部工作原理和技术实现,开发者可以创建出更高效、更易用的在线编辑工具。

    绝对好用的web编辑器

    【标题】:“绝对好用的Web编辑器” 在网页开发中,内容的创建与编辑是一项重要的任务,而“绝对好用的Web编辑...无论是个人博客、企业网站还是在线学习平台,都可以借助这样的编辑器提升用户体验,加速内容生产流程。

    163的web编辑器

    163的Web编辑器,通常指的是网易公司开发的一款在线文本编辑工具,广泛应用于新闻发布、内容创作等场景。这款编辑器以其易用性、功能丰富和兼容性好等特点,深受用户喜爱。以下是对163Web编辑器的详细解析: 一、...

    JBPM Web流程设计器

    而“JBPM Web流程设计器”是JBPM框架的一个组成部分,专为Web环境设计,允许用户通过浏览器来创建和编辑业务流程。 ### 一、流程设计器概述 JBPM Web流程设计器基于JavaScript和ExtJS库构建,提供了一个直观的图形...

    非常好用的web在线编辑器

    Web在线编辑器是一种基于网页的文本编辑工具,它允许用户在浏览器中进行文字处理,类似于桌面版的Word软件。这种编辑器通常采用富文本格式,支持字体、字号、颜色、对齐方式等样式设置,以及插入图片、链接、表格等...

    简单方便的web打印编辑器.rar

    描述中的“简单方便的web打印编辑器”进一步确认了该软件的主要特性,即它的用户界面友好,操作流程简洁,旨在优化用户的打印体验。这可能意味着编辑器提供了直观的UI设计,减少了学习曲线,让用户能快速上手。 ...

    web流程设计器(jsplumb+jqueryUI)拖拽功能

    总的来说,利用jsPlumb和jQuery UI,我们可以创建出一个功能强大的、用户友好的Web流程设计器,它的拖拽功能使得流程图的编辑变得简单易行。无论是用于内部开发还是对外提供服务,这样的工具都能够为用户提供极大的...

    工作流程编辑器!帮助大家

    【标题】:“工作流程编辑器!帮助大家” 【描述】:“自己一点点整理的!费了好大劲,在google code上面不能不能打包下载!所以贵了点” 这个标题和描述揭示了一个关于工作流程编辑器的重要信息,这是一款可能由...

    非常实用的Web编辑器

    "非常实用的Web编辑器"这一标题暗示了我们讨论的是一款功能强大且易于使用的在线或桌面应用程序,它的设计目标是简化Web开发流程,提供无缝的编码体验。 描述中的“小巧”意味着这款编辑器可能具有轻量级的特性,...

    基于Flex的Web流程设计器开发

    基于 Flex 的 Web 流程设计器开发 本文将详细介绍基于 Flex 的 Web 流程设计器的...3. 采用 GEF 框架可以快速开发出功能强大、交互性好的图形编辑器。 4. 在开发 Web 应用程序时,需要注意前端和后台的设计和实现。

    WEB版JQuery流程设计器 v2.0

    我们参考了很多相关流程设计器,现重新规划出一个真正好用和易于二次开发的流程设计工具,它具有【精巧、方便、实用】等优点。 使用主流技术,开源免费 兼容:IE7++、Chrome、Firefox 等主流浏览器

    JS流程图编辑器

    JS流程图编辑器是一种基于纯JavaScript技术开发的Web应用程序,专为用户在浏览器环境中创建、编辑和展示流程图而设计。这种编辑器的出现极大地提升了网页应用中流程图的交互性和用户体验,尤其适用于业务流程梳理、...

    一个用Javascript实现的web流程设计器

    【JavaScript Web流程设计器】是一种基于JavaScript技术开发的交互式工具,专用于在Web环境中创建、编辑和管理工作流程。这种设计器通常集成了图形用户界面,允许用户通过拖放操作来构建复杂的业务流程模型,而无需...

    activiti5.22-web流程设计器整合demo

    Web流程设计器是Activiti的核心组件之一,允许开发者在Web环境下直接设计、编辑和调试业务流程,极大地提高了工作效率。 这个demo中,我们首先需要将项目导入Eclipse这样的集成开发环境中。Eclipse是Java开发的常用...

Global site tag (gtag.js) - Google Analytics