采用d3开发流程设计器(一)搭建框架和节点拖拽

多年前接触过一个easyui写的一个流程设计器,功能蛮强大的,但时过境迁,以前的那种太过笨重,而且始终感觉运行起来太卡顿,最近公司不是特别忙,突然想采用d3来写个流程设计器。
流程设计器大概需求

  • 可以拖拽节点进行绘制流程图
  • 可以点击右键弹出菜单进行相应操作
  • 可以生成流程xml格式内容
  • 可以双击弹出属性配置
  • 遵循activity的流程图规则
  • 流程图可以整体拖动
  • 提供流程图的鹰眼查看功能
  • 提供流程图放大缩小功能
    目前只想到这些需求。

第一步:自然就是搭建框架结构, 左边为操作区域,右边为绘图区域:
采用d3开发流程设计器(一)搭建框架和节点拖拽_第1张图片
第二步:就是实现开始按钮,结束按钮的拖拽

通过mousedown事件来实现dom的拖拽

   moseItemMove (event,nodeType) {
                let odiv = $(event.target).closest(".flowNode").get(0);   //获取当前元素
                if(odiv==null){
                    return void(0);
                }
                let pos=GoingUtils.getElementPosition($("#flowLayout").get(0));
                let {x,y}=GoingUtils.getElementPosition(odiv);
                //需要实际
                let newDiv=$(odiv).clone(true).appendTo("#flowLayout");
                $(newDiv).css("position","absolute").css("opacity","0.8").css("left",x-pos.x).css("top",y-pos.y).css("border","1px solid #dfdfdf").css("width","150");
                newDiv=newDiv.get(0);
                //算出鼠标相对元素的位置
                let disX = event.clientX - newDiv.offsetLeft;
                var disy = event.clientY - newDiv.offsetTop;
                let left = '',top='';
                document.onmousemove = (e)=>{
                    //用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
                    left = e.clientX - disX;
                    top = e.clientY - disy;
                    if(this.moverTimer!=null){
                        clearTimeout(this.moverTimer);
                    }
                    this.moverTimer=setTimeout(()=>{
                    //这里是限制拖动范围
                        if(top<0||left<180){
                            $(newDiv).css("cursor","not-allowed");
                            newDiv.style.left = left + 'px';
                            newDiv.style.top = top + 'px';
                            this.appendNode=false;
                        }else{
                            this.appendNode=true;
                            $(newDiv).css("cursor","inherit");
                            //绑定元素位置到positionX和positionY上面
                            //移动当前元素
                            newDiv.style.left = left + 'px';
                            newDiv.style.top = top + 'px';
                        }
                    },5);
                };
                document.onmouseup = (e) => {
                    document.onmousemove = null;
                    document.onmouseup = null;
                    this.appendSvgNode(newDiv,nodeType);
                };
            }

这样就实现了dom元素的拖拽操作。如果拖拽到设计区域,则进行svg节点的添加

第三步:进行svg元素的添加


/**
 * 绘制节点
 * @param nodeColor
 * @param nodeData
 * @param circleWidth
 * @param nodeText
 * @private
 */
FlowDesCtl.prototype._addNode=function({nodeColor,nodeData,circleWidth,nodeText}){
    this.svgObj.selectAll("rect")
        .attr("fill-opacity", 0)
        .attr("stroke-opacity", 0);


    function dragstarted(d) {
        if (d != null) {
            d.fx = d.x;
            d.fy = d.y;
        }
    }

    function dragged(d) {
        console.log(d,"====");
        if (d != null) {
            d.fx = window.d3.event.x;
            d.fy = window.d3.event.y;
            window.d3.select(this).attr("transform",`translate(${d.fx},${d.fy })`);
        }
    }

    function dragended(d) {
        if(d!=null){
            d.fx = null;
            d.fy = null;
        }
    }
    let {fx,fy}=nodeData;
    const node = this.svgObj.append("g")
    // .selectAll("g")
        .data([nodeData])
        .attr("fill", "currentColor")
        .attr("stroke-linecap", "round")
        .attr("stroke-linejoin", "round")
        .attr("class", "moveNode")
        .attr("transform",`translate(${fx},${fy})`)
        .style("cursor",`move)`)
        .call(window.d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended));


    node.append("rect")
        .attr("rx", 4)
        .attr("ry", 4)
        .attr("id", (d)=>{
            return "rect_"+d.id+"";
        })
        .attr("fill", "#fff")
        .attr("width",  (d)=> {
            return 10;
        })
        .attr("height",  (d)=> {
            console.log(d,"===height");
            return 10;
        })
        .attr("stroke", "red")
        .attr("stroke-width", 1)
        .attr("transform",`translate(${15},${20})`)
        .attr("fill-opacity", 1)
        .attr("stroke-opacity", 1)
    ;

    node.append("circle")
        .attr("r", circleWidth)
        .attr("fill", nodeColor)
        .on("click", d => {
            this.svgObj.selectAll("rect")
                .attr("fill-opacity", 0)
                .attr("stroke-opacity", 0);
            window.d3.select("#"+"rect_"+d.id)
                .attr("fill-opacity", 1)
                .attr("stroke-opacity", 1);
            console.log(d,"====");
        });
    // .attr("cx", 20)
    // .attr("cy", 20);

    node.append("text")
        .attr("x", -circleWidth/2)
        .attr("y", "0.31em")
        .text(nodeText)
        .attr("fill", "#fff")
        .attr("stroke", "white")
        .attr("stroke-width", "0.5px")
        .style('stroke',"#FFF")
        .attr("stroke", "#fff");
};

这样就成功的实现了开始节点和结束节点进行拖拽绘制的功能。
采用d3开发流程设计器(一)搭建框架和节点拖拽_第2张图片
具体代码会整个设计器写完后附上github地址。

你可能感兴趣的:(d3,流程设计器,js,javascript,vue)