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;
});最后想知道作者大大,连线上写字是如何实现的,挺急的!!!
添加回答
举报