採用d3開發流程設計器(五)實現節點間線條的拖拽變換

一晃這設計器也寫了快一週了,基本功能已經出來咯。但完全做完應該還需要個把月吧。
這節我們介紹下節點間線條的拖拽變換的功能:
需求:
1、點擊線條,會在線條倆端生成2個拖拽節點。
2、點擊拖拽節點可以變換線條的起始位置或者是結束位置。
效果圖:
在這裏插入圖片描述
點擊拖拽節點進行線條位置的變換

在這裏插入圖片描述

核心代碼:
點擊線條繪製拖拽節點:


/**
 * 創建激活的link
 * @private
 */
FlowLink.prototype._createLinkActiveNode = function (d, linkId, linkInfos) {
    let dexObj=this;
    let {sourceDragType, linkTargetDragType, sourceNode, targetNode} = linkInfos;
    let startX = sourceNode.fx + sourceNode.linkDrage[sourceDragType]["cx"];
    let startY = sourceNode.fy + sourceNode.linkDrage[sourceDragType]["cy"];
    let endX = targetNode.fx + targetNode.linkDrage[linkTargetDragType]["cx"];
    let endY = targetNode.fy + targetNode.linkDrage[linkTargetDragType]["cy"];
    //變更前 進行數據初始化
    let dragstarted=function(d){
        dexObj.flowDesCtl.options.nodeOutTime=500;
        d.linkMv={};
        d.linkMv.sourceDragType=sourceDragType;
        d.linkMv.linkTargetDragType=linkTargetDragType;
        d.linkMv.startXPos=startX;
        d.linkMv.startYPos=startY;
        d.linkMv.endXPos=endX;
        d.linkMv.endYPos=endY;
        d.linkMv.moveLinkId=linkId;
        d.linkMv.sourceNode=sourceNode;
        d.linkMv.targetNode=targetNode;
    };

    //變更啓始節點
    let draggSourced=function(d){
        d.change="changeSource";
        //獲取拖拽的位置
        d.linkMv.mvX = window.d3.event.x;
        d.linkMv.mvY = window.d3.event.y;
        //獲取以前的結束位置
        let endXPos = d.linkMv.endXPos;
        let endYPos = d.linkMv.endYPos;
        //調整拖拽節點的位置
        window.d3.select(this).attr("transform", `translate(${d.linkMv.mvX+4},${d.linkMv.mvY+4})`);
        //調整線條的位置
        window.d3.select("#" + d.linkMv.moveLinkId).attr("d", `M${d.linkMv.mvX} ${d.linkMv.mvY}L${endXPos} ${endYPos}`);
    };

    //變更結束節點
    let draggTargeted=function(d){
        d.change="changeTarget";
        //獲取拖拽的位置
        d.linkMv.mvX = window.d3.event.x;
        d.linkMv.mvY = window.d3.event.y;
        //獲取以前的結束位置
        let startXPos = d.linkMv.startXPos;
        let startYPos = d.linkMv.startYPos;
        //調整拖拽節點的位置
        window.d3.select(this).attr("transform", `translate(${d.linkMv.mvX+4},${d.linkMv.mvY+4})`);
        //調整線條的位置
        window.d3.select("#" + d.linkMv.moveLinkId).attr("d", `M${startXPos} ${startYPos}L${d.linkMv.mvX} ${d.linkMv.mvY}`);
    };




    //變更結束
    let dragended=function(d){
        dexObj.flowDesCtl.options.nodeOutTime=500;
        let targetRect=window.d3.select(this);
        //變更目標
        if(d.change==="changeTarget"){
            dexObj._changeTargetNode(targetRect,d.linkMv.moveLinkId,d);
        }else{
            dexObj._changeSourceNode(targetRect,d.linkMv.moveLinkId,d);
        }
        //清空以前的值
        for(let prop in d.linkMv){
            d.linkMv[prop]=null;
        }
        //移除緩存的數據
        d.linkMv=null;
        delete  d.linkMv;
    };


    let rectWidth=12;
    this.flowDesCtl.svgObj.append("rect")
        .attr("rx", '2')
        .attr("ry", '2')
        .data([sourceNode])
        .attr("width", rectWidth)
        .attr("class", "changeLinkNode")
        .attr("height", rectWidth)
        .attr("nodeType", "activeNode")
        .attr("fill", "rgb(0, 255, 0)")
        .attr("stroke", "#333")
        .attr("stroke-width", "1px")
        .style("cursor", `move)`)
        .attr("transform", `translate(${startX-rectWidth/2},${startY-rectWidth/2})`)
        .call(window.d3.drag()
            .on("start", dragstarted)
            .on("drag", draggSourced)
            .on("end", dragended));


    this.flowDesCtl.svgObj.append("rect")
        .attr("rx", '4')
        .attr("ry", '4')
        .data([targetNode])
        .attr("class", "changeLinkNode")
        .attr("width", rectWidth)
        .attr("height", rectWidth)
        .attr("nodeType", "activeNode")
        .attr("fill", "rgb(0, 255, 0)")
        .attr("stroke", "#333")
        .attr("stroke-width", "1px")
        .style("cursor", `move`)
        .attr("transform", `translate(${endX-rectWidth/2},${endY-rectWidth/2})`)
        .call(window.d3.drag()
            .on("start", dragstarted)
            .on("drag", draggTargeted)
            .on("end", dragended));

};

拖拽完後調整線條位置

/**
 * 改變啓始節點
 * @param d
 * @private
 */
FlowLink.prototype._changeSourceNode= function (targetRect,linkId,d) {
    if(this.linkArys[linkId]==null){
        return void(0);
    }
    let dexObj=this.flowDesCtl;
    let {sourceDragType,linkTargetDragType,sourceNode,targetNode}=this.linkArys[linkId];
    //計算啓始位置
    let {startXPos,startYPos}=this.getNodePos(sourceNode,sourceDragType);
    //計算結束位置
    let endNodePos=this.getNodePos(targetNode,linkTargetDragType);
    //判斷目標節點信息是否存在  如果不存在 則還原線條
    if(this.flowDesCtl.linkTarget==null){
        this._setSourceLinkPostion({drageType:sourceDragType,linkId,targetRect,d,startXPos,startYPos,endXPos:endNodePos["startXPos"],endYPos:endNodePos["startYPos"]});
    }else{
        //   如果存在 也需要判斷 出來的線條是否存在重複線條 如果存在重複線條也是還原
        if (!this.hasLink({sourceNode:dexObj.linkTarget,sourceDragType:dexObj.linkTargetDragType,targetNode,targetDragType:linkTargetDragType})) {
            //需要將以前的關聯關係刪除
            this.delSourceRelLink(sourceNode,sourceDragType,linkId,targetNode,linkTargetDragType);
            //重新變更啓始節點的關聯信息
            this.changeSourceRelLink({sourceNode:dexObj.linkTarget,sourceDragType:dexObj.linkTargetDragType,linkId,targetNode,linkTargetDragType});
            //計算啓始位置
            let newNodePos=this.getNodePos(dexObj.linkTarget,dexObj.linkTargetDragType);
            //重新設置邊線位置
            this._setSourceLinkPostion({drageType:dexObj.linkTargetDragType,linkId,targetRect,d,startXPos:newNodePos["startXPos"],startYPos:newNodePos["startYPos"],endXPos:endNodePos["startXPos"],endYPos:endNodePos["startYPos"]});
        }else{
            this._setSourceLinkPostion({drageType:sourceDragType,linkId,targetRect,d,startXPos,startYPos,endXPos:endNodePos["startXPos"],endYPos:endNodePos["startYPos"]});
        }
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章