一晃這設計器也寫了快一週了,基本功能已經出來咯。但完全做完應該還需要個把月吧。
這節我們介紹下節點間線條的拖拽變換的功能:
需求:
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"]});
}
}
};