前面三節完成了開始、結束、普通節點的拖拽生成,這些都還比較簡單,這節來實現下線條都繪製以及拖拽相關功能:
需求:
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("線條目標節點不存在,移除");
}
}))
;
};