2 回答

TA貢獻3條經驗 獲得超3個贊
設計思路:
對關系進行分組,指向兩個相同節點為一組,記錄下同組數據length,即兩節點間關系線條數。
???? //關系分組 ?
??? var linkGroup = {}; ?
??? //對連接線進行統計和分組,不區分連接線的方向,只要屬于同兩個實體,即認為是同一組 ?
??? var linkmap = {}; ?
??? for(var i=0; i<links.length; i++){ ?
??????? var key = links[i].source<links[i].target?links[i].source+':'+links[i].target:links[i].target+':'+links[i].source; ?
??????? if(!linkmap.hasOwnProperty(key)){ ?
??????????? linkmap[key] = 0; ?
??????? } ?
??????? linkmap[key]+=1; ?
??????? if(!linkGroup.hasOwnProperty(key)){ ?
??????????? linkGroup[key]=[]; ?
??????? } ?
??????? linkGroup[key].push(links[i]); ?
??? }?對連線進行對稱編號({-1,0,1}、{-2,-1,0,1,-2}……),編號為0的線在中間,使連線對稱分布
for(var i=0; i<links.length; i++){ ?
??????? var key = links[i].source<links[i].target?links[i].source+':'+links[i].target:links[i].target+':'+links[i].source; ?
??????? links[i].size = linkmap[key]; ?
??????? //同一組的關系進行編號 ?
??????? var group = linkGroup[key]; ?
??????? //給節點分配編號 ?
??????? setLinkNumber(group); ?
??? }function setLinkNumber(group){? ?
??? if(group.length==0) return;
??? if(group.length==1){
?? ??? ?group[0].linknum = 0;
?? ??? ?return;
??? }
??? var maxLinkNumber = group.length%2==0?group.length/2:(group.length-1)/2;
?? ?
? ??? ?var startLinkNum = -maxLinkNumber;
?????? for(var i = 0;i<group.length;i++){
?????????? group[i].linknum = startLinkNum++;
?????? }
}連線初始化,涉及到一些坐標的運算,畫了個圖可能好理解一點,我們的目標就是計算坐標(x1,y1),(x2,y2),p點,q點坐標。我們知道O1,O2坐標以及他們的半徑
以下是計算過程
edges_path.attr("d", function(d) { ?
?? ??????? ??? ?var tan = Math.abs((d.target.y - d.source.y)/(d.target.x - d.source.x)); //圓心連線tan值
??????????????? var x1 = d.target.x - d.source.x > 0 ? Math.sqrt(d.sourceRadius*d.sourceRadius/(tan*tan + 1)) + d.source.x :
???????????????????? d.source.x - Math.sqrt(d.sourceRadius*d.sourceRadius/(tan*tan + 1)); //起點x坐標
??????????????? var y1 = d.target.y - d.source.y > 0 ? Math.sqrt(d.sourceRadius*d.sourceRadius*tan*tan/(tan*tan + 1)) + d.source.y :
??????????????????? d.source.y - Math.sqrt(d.sourceRadius*d.sourceRadius*tan*tan/(tan*tan + 1)); //起點y坐標
??????????????? var x2 = d.target.x - d.source.x > 0 ? d.target.x - Math.sqrt(d.targetRadius*d.targetRadius/(1+tan*tan)) :
??????????????????????? d.target.x + Math.sqrt(d.targetRadius*d.targetRadius/(1+tan*tan));//終點x坐標
??????????????? var y2 = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt(d.targetRadius*d.targetRadius*tan*tan/(1+tan*tan)) :
??????????????????? d.target.y + Math.sqrt(d.targetRadius*d.targetRadius*tan*tan/(1+tan*tan));//終點y坐標
??????????????? if(d.target.x - d.source.x == 0 || tan == 0){ //斜率無窮大的情況或為0時
?????????????? ??? ?y1 = d.target.y - d.source.y > 0 ? d.source.y + d.sourceRadius:d.source.y - d.sourceRadius;
?????????????? ??? ?y2 = d.target.y - d.source.y > 0 ? d.target.y - d.targetRadius:d.target.y + d.targetRadius;
??????????????? }
?? ???????????? if(d.linknum==0){//設置編號為0的連接線為直線,其他連接線會均分在兩邊 ?
?? ??????????? ??? ?d.x_start = x1;
?? ??????????? ??? ?d.y_start = y1;
?? ??????????? ??? ?d.x_end = x2;
?? ??????????? ??? ?d.y_end = y2;
?? ??????????? ??? ?return 'M'+x1+' '+y1+' L '+ x2 +' '+y2;
?? ???????????? }
?? ???????????? var a = d.sourceRadius > d.targetRadius ? d.targetRadius*d.linknum/6 : d.sourceRadius*d.linknum/6;
?? ???????????? var xm =d.target.x - d.source.x > 0 ? d.source.x + Math.sqrt((d.sourceRadius*d.sourceRadius-a*a)/(1+tan*tan)):
?? ??????????? ??? ?d.source.x - Math.sqrt((d.sourceRadius*d.sourceRadius-a*a)/(1+tan*tan));
?? ???????????? var ym =d.target.y - d.source.y > 0 ? d.source.y + Math.sqrt((d.sourceRadius*d.sourceRadius-a*a)*tan*tan/(1+tan*tan)):
?? ??????????? ??? ?d.source.y - Math.sqrt((d.sourceRadius*d.sourceRadius-a*a)*tan*tan/(1+tan*tan));
?? ???????????? var xn =d.target.x - d.source.x > 0 ? d.target.x - Math.sqrt((d.targetRadius*d.targetRadius-a*a)/(1+tan*tan)):
?? ??????????? ??? ?d.target.x + Math.sqrt((d.targetRadius*d.targetRadius-a*a)/(1+tan*tan));
?? ???????????? var yn =d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt((d.targetRadius*d.targetRadius-a*a)*tan*tan/(1+tan*tan)):
?? ??????????? ??? ?d.target.y + Math.sqrt((d.targetRadius*d.targetRadius-a*a)*tan*tan/(1+tan*tan));
?? ???????????? if(d.target.x - d.source.x == 0 || tan == 0){//斜率無窮大或為0時
?? ??????????? ??? ?ym = d.target.y - d.source.y > 0 ? d.source.y + Math.sqrt(d.sourceRadius*d.sourceRadius-a*a):d.source.y - Math.sqrt(d.sourceRadius*d.sourceRadius-a*a);
?? ??????????? ??? ?yn = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt(d.targetRadius*d.targetRadius-a*a):d.target.y + Math.sqrt(d.targetRadius*d.targetRadius-a*a);
?? ???????????? }
?? ??????????? ?
?? ???????????? var k = (x1-x2)/(y2-y1);//連線垂線的斜率
?? ???????????? var dx = Math.sqrt(a*a/(1+k*k)); //相對垂點x軸距離
??????????????? var dy = Math.sqrt(a*a*k*k/(1+k*k)); //相對垂點y軸距離
??????????????? if((y2-y1) == 0){
??????????????????? dx = 0;
??????????????????? dy = Math.sqrt(a*a);
??????????????? }
?? ???????????? if(a > 0){
?? ??????????? ??? ?var xs = k > 0 ? xm - dx : xm + dx;
?? ??????????? ??? ?var ys = ym - dy;
?? ??????????? ??? ?var xt = k > 0 ? xn - dx : xn + dx;
?? ??????????? ??? ?var yt = yn - dy;
?? ???????????? }else{
?? ??????????? ??? ?var xs = k > 0 ? xm + dx : xm - dx;
??????????????????? var ys = ym + dy;
??????????????????? var xt = k > 0 ? xn + dx : xn - dx;
??????????????????? var yt = yn + dy;
?? ???????????? }
?? ???????????? //記錄連線起始和終止坐標,用于定位線上文字
?? ???????????? d.x_start = x1;
??????????????? d.y_start = y1;
??????????????? d.x_end = x2;
??????????????? d.y_end = y2;
?? ???????????? return 'M'+xs+' '+ys+' L '+ xt +' '+yt;
?? ?????????? });最后想知道作者大大,連線上寫字是如何實現的,挺急的?。?!
添加回答
舉報