一晃这设计器也写了快一周了,基本功能已经出来咯。但完全做完应该还需要个把月吧。
这节我们介绍下节点间线条的拖拽变换的功能:
需求:
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"]});
}
}
};