採用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("線條目標節點不存在,移除");
            }
        }))
    ;
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章