采用d3开发流程设计器(四)实现线条的绘制,以及线条的箭头

前面三节完成了开始、结束、普通节点的拖拽生成,这些都还比较简单,这节来实现下线条都绘制以及拖拽相关功能:
需求:
1、拖拽生成线条,连接2个节点
2、拖拽节点的时候 线条跟着移动
3、选中线条变换样式
4、右键点击可以删除线条
5、线条末端带上箭头

效果大概:
在这里插入图片描述
核心函数有:

绘制箭头

/**
 * 绘制箭头
 * @param link
 * @param linkArrowId
 * @private
 */
FlowDesCtl.prototype._addLinkArrow=function (link,linkArrowId) {
    //添加marker标签及其属性
    var arrowMarker = link.append("marker")
        .attr("id","arrow"+linkArrowId)
        .attr("markerUnits","strokeWidth")
        .attr("markerWidth",12)
        .attr("markerHeight",12)
        .attr("viewBox","0 0 12 12")
        .attr("refX",13)
        .attr("refY",6)
        .attr("orient","auto");

    //绘制直线箭头
    var arrow_path = "M2,2 L10,6 L2,10 L6,6 L2,2";
    arrowMarker.append("path")
        .attr("d",arrow_path)
        .attr("fill",this.options.linkColor);
};

箭头跟线条关联起来

/**
 * 添加线条
 * @param d
 * @param nodeData
 * @private
 */
FlowDesCtl.prototype._addLink=function (d,nodeData,drageType) {
    //如果线条不存在 才需要这么操作
    const link = this.svgObj.append("g")
        .attr("fill", "none")
        .attr("stroke", this.options.linkColor)
        .data([nodeData])
        .attr("stroke-opacity", 1)
        .attr("stroke-width", 1)
        .attr("id", (d)=>{
            d.curLinkParentId="link_"+drageType+"_"+GoingUtils.getUUid(10);
            return d.curLinkParentId;
        })
        .on("click", (d) => {
           
        });

    let linkArrowId=GoingUtils.getUUid(10);
    //绘制箭头
    this._addLinkArrow(link,linkArrowId);

    link.append("path")
        .attr("id", (d)=>{
            if(d.linkAdded==null){
                d.linkAdded={};
            }
            d.linkAdded[drageType]=true;
            d.curLinkId="link_"+drageType+"_"+GoingUtils.getUUid(10);
            return d.curLinkId;
        })
        .attr("marker-end","url(#"+"arrow"+linkArrowId+")")
        .attr("d", (d)=>{
            return `M${d.linkDrage[drageType].startX} ${d.linkDrage[drageType].startY}L${d.linkDrage[drageType].endX} ${d.linkDrage[drageType].endY}`;
        })

    ;
};

拖拽节点生成线条


/**
 * 添加外框生成线条的节点
 * @param borderNode
 * @param nodeData
 * @param cx
 * @param cy
 * @private
 */
FlowDesCtl.prototype._addLinkBorderNode=function({borderNode,nodeData,cx,cy,drageType}){
    let dexObj=this;
    /**
     * 节点圆形
     */
    borderNode.append("circle")
        .attr("r", '4')
        .attr("fill", "#99BBE8")
        .attr("stroke", "#ff7f0e")
        .attr("stroke-opacity", 0)
        .attr("stroke-width", 4)
        .attr("drageType", drageType)
        .attr("class","linkDrageNode")
        .attr("id",(d)=>{
            return 'drag_link_node_'+drageType+"_"+d.id;
        })
        .attr("cx", d=>{
            if(d.linkDrage[drageType]==null){
                d.linkDrage[drageType]={};
            }
            d.linkDrage[drageType]["cx"]=cx;
            return cx;
        })
        .attr("cy", d=>{
            if(d.linkDrage[drageType]==null){
                d.linkDrage[drageType]={};
            }
            d.linkDrage[drageType]["cy"]=cy;
            return cy;
        })
        .on("mouseover", function(d) {
            window.d3.select(this).attr("stroke-opacity",1);
            var _drageType=window.d3.select(this).attr("drageType");
            dexObj.linkTarget=d;
            dexObj.linkTargetDragType=_drageType;
            dexObj.linkTargetId=window.d3.select(this).attr("id");
        })
        .on("mouseout", function(d) {
            dexObj.linkTarget=null;
            dexObj.linkTargetId=null;
            dexObj.linkTargetDragType=null;
            window.d3.select(this).attr("stroke-opacity",0);
        })
        .call(window.d3.drag().on("start", function(d){
            //进行节点线条拖拽操作
            if (d != null) {
                if(dexObj.linkTimer!=null){
                    clearTimeout(dexObj.linkTimer);
                }
                //获取当前节点拖拽类型位置
                let _drageType=window.d3.select(this).attr("drageType");
                d.curDrageType=_drageType;
                if(d.linkDrage[_drageType]==null){
                    return void(0);
                }
                dexObj.linkTimer=setTimeout( ()=>{
                    //设置开始坐标
                    d.linkDrage[_drageType].startX= d.fx+d.linkDrage[_drageType]["cx"];
                    d.linkDrage[_drageType].startY= d.fy+d.linkDrage[_drageType]["cy"];
                    // //设置结束坐标
                    d.linkDrage[_drageType].endX= d.linkDrage[_drageType].startX;
                    d.linkDrage[_drageType].endY= d.linkDrage[_drageType].startY;
                    //创建一条空的线条
                    dexObj._addLink(d,nodeData,_drageType);
                    dexObj.addLinkFlag=true;
                },100);
            }
        }).on("drag", function(d){
            let _drageType=window.d3.select(this).attr("drageType");
            if(d!=null&&dexObj.addLinkFlag){
                let moveX=window.d3.event.x-d.linkDrage[_drageType]["cx"];
                let moveY=window.d3.event.y-d.linkDrage[_drageType]["cy"];
                d.linkDrage[_drageType].endX= parseFloat(d.linkDrage[_drageType].startX)+parseFloat(moveX);
                d.linkDrage[_drageType].endY= parseFloat(d.linkDrage[_drageType].startY)+parseFloat(moveY);
                window.d3.select("#"+d.curLinkId).attr("d", `M${d.linkDrage[_drageType].startX} ${d.linkDrage[_drageType].startY}L${d.linkDrage[_drageType].endX} ${d.linkDrage[_drageType].endY}`);
            }
        }).on("end", (d)=>{
            if(dexObj.linkTarget!=null){
                dexObj._endLinkDragAddLink(d);
            }else{
                let _drageType=d.curDrageType;
                d.linkDrage[_drageType].startX=null;
                d.linkDrage[_drageType].startY=null;
                d.linkDrage[_drageType].endX=null;
                d.linkDrage[_drageType].endY=null;
                window.d3.select("#"+d.curLinkId).remove();
                console.log("线条目标节点不存在,移除");
            }
        }))
    ;
};

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值