采用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"]});
        }
    }
};
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值