d3.js网络曲线路径控制 [英] d3.js network curved path control

查看:72
本文介绍了d3.js网络曲线路径控制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

//最新小提琴



我正在尝试构建此我可以控制弯曲路径以显示网络的特定图表。两个正确间隔的树干 - 然后是弯曲的树枝,分散给不同的人。

  var w = 600; 
var h = 600;


var data = [{
userName:You,
userImage:https://encrypted-tbn1.gstatic.com/ images?q = tbn:ANd9GcSTzjaQlkAJswpiRZByvgsb3CVrfNNLLwjFHMrkZ_bzdPOWdxDE2Q
},{
userName:Johnny,
userImage:https://crossovercomicblog.files.wordpress.com/2012/ 08 / johnny-depp-sexy.jpg
},{
userName:Jeri,
userImage:https://68.media.tumblr.com/ avatar_3b6d6241698f_128.png
},{
userName:Charlize,
userImage:https://cdn.imza.com/indir/logo/128/charlize- theron.png
},{
userName:Charlize,
userImage:https://cdn.imza.com/indir/logo/128/charlize- theron.png
},{
userName:Charlize,
userImage:https://cdn.imza.com/indir/logo/128/charlize- theron.png
},{
userName:Charlize,
userImage:https://cdn.imza.com/indir/logo/128/charlize- theron.png
},{
userName:Angelina,
userImage:http s://pbs.twimg.com/profile_images/713650489032908800/nO1dMt6M_400x400.jpg
},{
userName:Them,
userImage:https:// 68.media.tumblr.com/avatar_8f199caf2d82_128.png
}];

var viz = d3.select(#viz)
.append(svg)
.attr(width,w)
.attr (height,h)
.append(g)
.attr(transform,translate(40,100));


var patternsSvg = viz.append('g')
.attr('class','patterns');

var labelholder = viz.append(g)
.attr(class,labelholder);

var treeholder = viz.append(g)
.attr(class,treeholder);

var userholder = viz.append(g)
.attr(class,userholder);



var smallRadius = 20;
var bigRadius = 30;

var smallX = smallRadius +(bigRadius / 2);
var bigX =(bigRadius * 2)+(smallRadius / 2);

var verticalGap =(bigRadius * 2) - 5;

var count = data.length;


var extendedY =(count-2 *(smallRadius * 2))+((bigRadius * 2)* 2);
var arcRadiusLeft =(bigRadius / 2);
var arcRadiusRight = - (bigRadius / 2);


$ .each(数据,函数(索引,值){
var defs = patternsSvg.append('svg:defs');

//大设计
defs.append('svg:pattern')
.attr('id',index + - + value.userName.toLowerCase())
。 attr('width',1)
.attr('height',1)
.append('svg:image')
.attr('xlink:href',value.userImage )
.attr('x',0)
.attr('y',0)
.attr('width',bigRadius * 2)
.attr(' height',bigRadius * 2);

//小型设计
defs.append('svg:pattern')
.attr('id',index + - + value.userName.toLowerCase())
.attr('width',1)
.attr('height',1)
.append('svg:image')
.attr('xlink:href',value.userImage)
.attr('x',0)
.attr('y',0)
.attr('width ',smallRadius * 2)
.attr('height',smallRadius * 2);

} );



//绘制人圈
var circle = userholder.append(g)。selectAll(circle)
.data(数据);

circle
.enter()
.append(svg:circle)
.attr(id,function(d){
return d.userName.toLowerCase();
})
.attr(r,function(d,i){
var rad = smallRadius;

//第一个和最后一个项目 - 所以你和他们
if(i == 0 || i == count - 1){
rad = bigRadius;
}
return rad;
})
.attr(cx,function(d,i){
var cx;
if(i == 0){
cx = 0; //第一个
}否则if(i == count - 1){
cx = bigX; // last last
} else {
cx = smallX; //小的
}
返回cx;
})
.attr(cy,函数(d,i){
var cy;
if(i == 0){
cy = 0;
}否则if(i == count - 1){
cy = verticalGap *(i-1)+ extendedY + bigRadius ;
}其他{
cy = verticalGap * i
}
返回cy;
})
.style(填充 ,function(d,i){
var id = i + - + d.userName.toLowerCase(); //小圆圈

//大圆圈
if(i == 0 || i == count - 1){
id = i + - + d .userName.toLowerCase();
}
返回url(#+ id +);
});
//绘制人圈



// __标签
var labelholder = d3.select(。labelholder);

// __输入
var labels = labelholder.selectAll(text)
.data(data);

labels.enter()
.append(text)
.attr(text-anchor,left)

/ / __ update
标签
.attr(x,函数(d,i){

var displacement =(bigRadius / 2)+ smallRadius;
var cx =(smallRadius * 2);
if(i == 0){
cx = bigRadius;
displacement = bigRadius / 2;
}
if(i == count - 1){
cx =(bigRadius * 2)+ bigRadius;
displacement = bigRadius;
}

cx + = displacement;

返回cx;
})
.attr(y,函数(d,i){
var cy = verticalGap * i;
if(i == count - 1){
cy + = extendedY - (bigRadius / 2);
}
return cy;
})
.text(function(d) ){
return d.userName;
});
// __ labels


var backbone = treeholder.append(g)
.append(svg:path);

backbone.attr(d,函数(d,i){
var sx =(bigRadius / 2) - (bigRadius / 2);
var tx =( bigRadius / 2) - (bigRadius / 2);

var r = smallRadius;
if(i == 0 || i == count - 1){
r = bigRadius ;
}

var sy =((r / 2)* i)+(r);
var ty = verticalGap *(count - 2) - arcRadiusLeft;
var dr = 0;

返回M+ sx +,+ sy +A+ dr +,+ dr +0 0,1+ tx + ,+ ty;
});

var displaceYBackboneRight =(bigRadius / 2)+ 5;

var backbone = treeholder.append(g)
.append(svg:path);

backbone.attr(d,函数(d,i){
var sx =(bigRadius * 2)+ smallRadius / 2;
var tx =(bigRadius * 2)+ smallRadius / 2;

var r = smallRadius;
if(i == 0 || i == count - 1){
r = bigRadius;
}

var sy =((r / 2)* i)+(r)+ smallRadius + displaceYBackboneRight;

var ty = verticalGap *(count - 2)+ extendedY;

var dr = 0;

返回M+ sx +,+ sy +A+ dr +,+ dr +0 0,1+ tx +,+ ty;
});


//左边的分支
var leftpath = treeholder.append(g)。selectAll(path.leftpath)
.data(data )

leftpath
.enter()。append(svg:path)
.attr(class,function(d){
returnleftpath ;
});

leftpath.attr(d,函数(d,i){
var sx = 0;
var tx = arcRadiusLeft;

var sy = verticalGap * i - arcRadiusLeft;
var ty = verticalGap * i;

if(i!= 0&& i!= count - 1){
return M+ sx +,+ sy +A+ arcRadiusLeft +,+ arcRadiusLeft +0 0,0+ tx +,+ ty;
}

});




//左边的分支
var rightpath = treeholder.append(g)。selectAll(path.rightpath)
.data(data)

rightpath
.enter()。append(svg:path)
.attr(class,function(d) {
返回rightpath;
});

rightpath.attr(d,函数(d,i){
var sx =(bigRadius * 2)+(smallRadius / 2);
var tx = arcRadiusRight +(bigRadius * 2)+(smallRadius / 2);

var sy = verticalGap * i +(bigRadius / 2);
var ty = verticalGap * i + arcRadiusRight +(bigRadius / 2);

if(i!= 0&& i!= count - 1){
returnM+ sx +,+ sy +A+ arcRadiusLeft +,+ arcRadiusLeft +0 0,0+ tx +,+ ty;
}


});

// old
http://jsfiddle.net/NYEaX/1811/



所以这里的关键是要创建小弧正确使用数学。



< img src =https://i.stack.imgur.com/f2k5q.pngalt =在此输入图像说明>



类似于这个

  path.attr(d,函数(d,i){
const sx = 0;
const sy = height / 2;

// width - 从主题a到主题的图表总宽度b

const a = width / 2;
// a - 主题a和中心之间的距离

const b =(1.5-i)* distanceBetween;
// b - 特征1和特征2之间的距离(点之间)

const c = Math.sqrt(a * a + b * b);
// c - 是主题a和特征之间的对角线距离1

const angle =数学.atan(A / B);
//角度 - 在组之间加上

const r = 1/2 * c / Math.cos(angle);
// r - 1/2 c的距离除以角度的cos - 将创建一个绘制弧的半径


//也等于c / b *(c / 2)
// const r = c / b *(c / 2);
返回M $ {sx},$ {sy} A $ {r},$ {r} 0 0,$ {b> 0?1:0} $ {width},$ {height / 2} `;
});


解决方案

//最新js小提琴 - 稳定控制所有人适当的路径 - 基于blackmiaool的答案。



http ://jsfiddle.net/rbLk2fbe/2/

  var w = 600; 
var h = 600;


var data = [{
userName:You,
userImage:https://encrypted-tbn1.gstatic.com/ images?q = tbn:ANd9GcSTzjaQlkAJswpiRZByvgsb3CVrfNNLLwjFHMrkZ_bzdPOWdxDE2Q
},{
userName:Johnny,
userImage:https://crossovercomicblog.files.wordpress.com/2012/ 08 / johnny-depp-sexy.jpg
},{
userName:Jeri,
userImage:https://68.media.tumblr.com/ avatar_3b6d6241698f_128.png
},{
userName:Charlize,
userImage:https://cdn.imza.com/indir/logo/128/charlize- theron.png
},{
userName:Charlize,
userImage:https://cdn.imza.com/indir/logo/128/charlize- theron.png
},{
userName:Charlize,
userImage:https://cdn.imza.com/indir/logo/128/charlize- theron.png
},{
userName:Charlize,
userImage:https://cdn.imza.com/indir/logo/128/charlize- theron.png
},{
userName:Angelina,
userImage:http s://pbs.twimg.com/profile_images/713650489032908800/nO1dMt6M_400x400.jpg
},{
userName:Them,
userImage:https:// 68.media.tumblr.com/avatar_8f199caf2d82_128.png
}];

var viz = d3.select(#viz)
.append(svg)
.attr(width,w)
.attr (height,h)
.append(g)
.attr(transform,translate(40,100));


var patternsSvg = viz.append('g')
.attr('class','patterns');

var labelholder = viz.append(g)
.attr(class,labelholder);

var treeholder = viz.append(g)
.attr(class,treeholder);

var userholder = viz.append(g)
.attr(class,userholder);



var smallRadius = 20;
var bigRadius = 30;

var smallX = smallRadius +(bigRadius / 2);
var bigX =(bigRadius * 2)+(smallRadius / 2);

var verticalGap =(bigRadius * 2) - 5;

var count = data.length;


var extendedY =(count-2 *(smallRadius * 2))+((bigRadius * 2)* 2);
var arcRadiusLeft =(bigRadius / 2);
var arcRadiusRight = - (bigRadius / 2);


$ .each(数据,函数(索引,值){
var defs = patternsSvg.append('svg:defs');

//大设计
defs.append('svg:pattern')
.attr('id',index + - + value.userName.toLowerCase())
。 attr('width',1)
.attr('height',1)
.append('svg:image')
.attr('xlink:href',value.userImage )
.attr('x',0)
.attr('y',0)
.attr('width',bigRadius * 2)
.attr(' height',bigRadius * 2);

//小型设计
defs.append('svg:pattern')
.attr('id',index + - + value.userName.toLowerCase())
.attr('width',1)
.attr('height',1)
.append('svg:image')
.attr('xlink:href',value.userImage)
.attr('x',0)
.attr('y',0)
.attr('width ',smallRadius * 2)
.attr('height',smallRadius * 2);

} );



//绘制人圈
var circle = userholder.append(g)。selectAll(circle)
.data(数据);

circle
.enter()
.append(svg:circle)
.attr(id,function(d){
return d.userName.toLowerCase();
})
.attr(r,function(d,i){
var rad = smallRadius;

//第一个和最后一个项目 - 所以你和他们
if(i == 0 || i == count - 1){
rad = bigRadius;
}
return rad;
})
.attr(cx,function(d,i){
var cx;
if(i == 0){
cx = 0; //第一个
}否则if(i == count - 1){
cx = bigX; // last last
} else {
cx = smallX; //小的
}
返回cx;
})
.attr(cy,函数(d,i){
var cy;
if(i == 0){
cy = 0;
}否则if(i == count - 1){
cy = verticalGap *(i-1)+ extendedY + bigRadius ;
}其他{
cy = verticalGap * i
}
返回cy;
})
.style(填充 ,function(d,i){
var id = i + - + d.userName.toLowerCase(); //小圆圈

//大圆圈
if(i == 0 || i == count - 1){
id = i + - + d .userName.toLowerCase();
}
返回url(#+ id +);
});
//绘制人圈



// __标签
var labelholder = d3.select(。labelholder);

// __输入
var labels = labelholder.selectAll(text)
.data(data);

labels.enter()
.append(text)
.attr(text-anchor,left)

/ / __ update
标签
.attr(x,函数(d,i){

var displacement =(bigRadius / 2)+ smallRadius;
var cx =(smallRadius * 2);
if(i == 0){
cx = bigRadius;
displacement = bigRadius / 2;
}
if(i == count - 1){
cx =(bigRadius * 2)+ bigRadius;
displacement = bigRadius;
}

cx + = displacement;

返回cx;
})
.attr(y,函数(d,i){
var cy = verticalGap * i;
if(i == count - 1){
cy + = extendedY - (bigRadius / 2);
}
return cy;
})
.text(function(d) ){
return d.userName;
});
// __ labels


var backbone = treeholder.append(g)
.append(svg:path);

backbone.attr(d,函数(d,i){
var sx =(bigRadius / 2) - (bigRadius / 2);
var tx =( bigRadius / 2) - (bigRadius / 2);

var r = smallRadius;
if(i == 0 || i == count - 1){
r = bigRadius ;
}

var sy =((r / 2)* i)+(r);
var ty = verticalGap *(count - 2) - arcRadiusLeft;
var dr = 0;

返回M+ sx +,+ sy +A+ dr +,+ dr +0 0,1+ tx + ,+ ty;
});

var displaceYBackboneRight =(bigRadius / 2)+ 5;

var backbone = treeholder.append(g)
.append(svg:path);

backbone.attr(d,函数(d,i){
var sx =(bigRadius * 2)+ smallRadius / 2;
var tx =(bigRadius * 2)+ smallRadius / 2;

var r = smallRadius;
if(i == 0 || i == count - 1){
r = bigRadius;
}

var sy =((r / 2)* i)+(r)+ smallRadius + displaceYBackboneRight;

var ty = verticalGap *(count - 2)+ extendedY;

var dr = 0;

返回M+ sx +,+ sy +A+ dr +,+ dr +0 0,1+ tx +,+ ty;
});


//左边的分支
var leftpath = treeholder.append(g)。selectAll(path.leftpath)
.data(data )

leftpath
.enter()。append(svg:path)
.attr(class,function(d){
returnleftpath ;
});

leftpath.attr(d,函数(d,i){
var sx = 0;
var tx = arcRadiusLeft;

var sy = verticalGap * i - arcRadiusLeft;
var ty = verticalGap * i;

if(i!= 0&& i!= count - 1){
return M+ sx +,+ sy +A+ arcRadiusLeft +,+ arcRadiusLeft +0 0,0+ tx +,+ ty;
}

});




//左边的分支
var rightpath = treeholder.append(g)。selectAll(path.rightpath)
.data(data)

rightpath
.enter()。append(svg:path)
.attr(class,function(d) {
返回rightpath;
});

rightpath.attr(d,函数(d,i){
var sx =(bigRadius * 2)+(smallRadius / 2);
var tx = arcRadiusRight +(bigRadius * 2)+(smallRadius / 2);

var sy = verticalGap * i +(bigRadius / 2);
var ty = verticalGap * i + arcRadiusRight +(bigRadius / 2);

if(i!= 0&& i!= count - 1){
returnM+ sx +,+ sy +A+ arcRadiusLeft +,+ arcRadiusLeft +0 0,0+ tx +,+ ty;
}


});


//latest fiddle http://jsfiddle.net/rbLk2fbe/2/

I am trying to build this particular chart where I can control the curved paths to show a network. Two trunks that are spaced correctly - and then curved branches that leaf off to the various people.

 var w = 600;
 var h = 600;


 var data = [{
   "userName": "You",
   "userImage": "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcSTzjaQlkAJswpiRZByvgsb3CVrfNNLLwjFHMrkZ_bzdPOWdxDE2Q"
 }, {
   "userName": "Johnny",
   "userImage": "https://crossovercomicblog.files.wordpress.com/2012/08/johnny-depp-sexy.jpg"
 }, {
   "userName": "Jeri",
   "userImage": "https://68.media.tumblr.com/avatar_3b6d6241698f_128.png"
 }, {
   "userName": "Charlize",
   "userImage": "https://cdn.imza.com/indir/logo/128/charlize-theron.png"
 },{
   "userName": "Charlize",
   "userImage": "https://cdn.imza.com/indir/logo/128/charlize-theron.png"
 },{
   "userName": "Charlize",
   "userImage": "https://cdn.imza.com/indir/logo/128/charlize-theron.png"
 },{
   "userName": "Charlize",
   "userImage": "https://cdn.imza.com/indir/logo/128/charlize-theron.png"
 },{
   "userName": "Angelina",
   "userImage": "https://pbs.twimg.com/profile_images/713650489032908800/nO1dMt6M_400x400.jpg"
 },  {
   "userName": "Them",
   "userImage": "https://68.media.tumblr.com/avatar_8f199caf2d82_128.png"
 }];

 var viz = d3.select("#viz")
   .append("svg")
   .attr("width", w)
   .attr("height", h)
   .append("g")
   .attr("transform", "translate(40,100)");


 var patternsSvg = viz.append('g')
   .attr('class', 'patterns');

 var labelholder = viz.append("g")
   .attr("class", "labelholder");

 var treeholder = viz.append("g")
   .attr("class", "treeholder");

 var userholder = viz.append("g")
   .attr("class", "userholder");



 var smallRadius = 20;
 var bigRadius = 30;

 var smallX = smallRadius + (bigRadius/2);
 var bigX = (bigRadius*2) + (smallRadius/2);

 var verticalGap = (bigRadius * 2) - 5;

 var count = data.length;


 var extendedY = (count-2 * (smallRadius*2)) + ((bigRadius*2) * 2);
 var arcRadiusLeft = (bigRadius / 2);
 var arcRadiusRight = -(bigRadius / 2);


 $.each(data, function(index, value) {
   var defs = patternsSvg.append('svg:defs');

   //big design   
   defs.append('svg:pattern')
     .attr('id', index + "--" + value.userName.toLowerCase())
     .attr('width', 1)
     .attr('height', 1)
     .append('svg:image')
     .attr('xlink:href', value.userImage)
     .attr('x', 0)
     .attr('y', 0)
     .attr('width', bigRadius * 2)
     .attr('height', bigRadius * 2);

   //small design
   defs.append('svg:pattern')
     .attr('id', index + "-" + value.userName.toLowerCase())
     .attr('width', 1)
     .attr('height', 1)
     .append('svg:image')
     .attr('xlink:href', value.userImage)
     .attr('x', 0)
     .attr('y', 0)
     .attr('width', smallRadius * 2)
     .attr('height', smallRadius * 2);

 });



 //plot people circles
 var circle = userholder.append("g").selectAll("circle")
   .data(data);

 circle
   .enter()
   .append("svg:circle")
   .attr("id", function(d) {
     return d.userName.toLowerCase();
   })
   .attr("r", function(d, i) {
     var rad = smallRadius;

     //first and last items -- so you and them
     if (i == 0 || i == count - 1) {
       rad = bigRadius;
     }
     return rad;
   })
   .attr("cx", function(d, i) {
     var cx;
     if (i == 0) {
       cx = 0; //first one 
     } else if (i == count - 1) {
       cx = bigX; //last one
     } else {
       cx = smallX; //small ones
     }
     return cx;
   })
   .attr("cy", function(d, i) {
     var cy;
     if (i == 0) {
       cy = 0;
     } else if (i == count - 1) {
       cy = verticalGap * (i-1) + extendedY + bigRadius;
     } else {
       cy = verticalGap * i
     }
     return cy;
   })
   .style("fill", function(d, i) {
     var id = i + "-" + d.userName.toLowerCase(); //small circles

     //large circles
     if (i == 0 || i == count - 1) {
       id = i + "--" + d.userName.toLowerCase();
     }
     return "url(#" + id + ")";
   });
 //plot people circles



 //__labels  
 var labelholder = d3.select(".labelholder");

 //__ enter
 var labels = labelholder.selectAll("text")
   .data(data);

 labels.enter()
   .append("text")
   .attr("text-anchor", "left")

 //__ update            
 labels
   .attr("x", function(d, i) {

     var displacement = (bigRadius/2) + smallRadius;
     var cx = (smallRadius * 2);
     if (i == 0) {
       cx = bigRadius;
       displacement = bigRadius/2;
     }
     if (i == count - 1) {
       cx = (bigRadius * 2) + bigRadius;
       displacement = bigRadius;
     }

     cx += displacement;

     return cx;
   })
   .attr("y", function(d, i) {
     var cy = verticalGap * i;
     if (i == count - 1) {
       cy += extendedY - (bigRadius/2);
     }
     return cy;
   })
   .text(function(d) {
     return d.userName;
   });
 //__labels


 var backbone = treeholder.append("g")
   .append("svg:path");

 backbone.attr("d", function(d, i) {
   var sx = (bigRadius / 2) - (bigRadius / 2);
   var tx = (bigRadius / 2) - (bigRadius / 2);

   var r = smallRadius;
   if (i == 0 || i == count - 1) {
     r = bigRadius;
   }

   var sy = ((r / 2) * i) + (r);
   var ty = verticalGap * (count - 2) - arcRadiusLeft;
   var dr = 0;

   return "M" + sx + "," + sy + "A" + dr + "," + dr + " 0 0,1 " + tx + "," + ty;
 });

var displaceYBackboneRight = (bigRadius / 2) + 5; 

 var backbone = treeholder.append("g")
   .append("svg:path");

 backbone.attr("d", function(d, i) {
   var sx = (bigRadius * 2) + smallRadius/2;
   var tx = (bigRadius * 2) + smallRadius/2;

   var r = smallRadius;
   if (i == 0 || i == count - 1) {
     r = bigRadius;
   }

   var sy = ((r / 2) * i) + (r) + smallRadius + displaceYBackboneRight;

   var ty = verticalGap * (count - 2) + extendedY;

   var dr = 0;

   return "M" + sx + "," + sy + "A" + dr + "," + dr + " 0 0,1 " + tx + "," + ty;
 });


 //branches on the left 
 var leftpath = treeholder.append("g").selectAll("path.leftpath")
   .data(data)

 leftpath
   .enter().append("svg:path")
   .attr("class", function(d) {
     return "leftpath";
   });

 leftpath.attr("d", function(d, i) {
   var sx = 0;
   var tx = arcRadiusLeft;

   var sy = verticalGap * i - arcRadiusLeft;
   var ty = verticalGap * i;

   if (i != 0 && i != count - 1) {
     return "M" + sx + "," + sy + "A" + arcRadiusLeft + "," + arcRadiusLeft + " 0 0,0 " + tx + "," + ty;
   }

 });




 //branches on the left 
 var rightpath = treeholder.append("g").selectAll("path.rightpath")
   .data(data)

 rightpath
   .enter().append("svg:path")
   .attr("class", function(d) {
     return "rightpath";
   });

 rightpath.attr("d", function(d, i) {
   var sx = (bigRadius*2) + (smallRadius/2);
   var tx = arcRadiusRight + (bigRadius*2) + (smallRadius/2);

   var sy = verticalGap * i + (bigRadius / 2);
   var ty = verticalGap * i + arcRadiusRight + (bigRadius / 2);

   if (i != 0 && i != count - 1) {
     return "M" + sx + "," + sy + "A" + arcRadiusLeft + "," + arcRadiusLeft + " 0 0,0 " + tx + "," + ty;
   }


 });

//old http://jsfiddle.net/NYEaX/1811/

So the key here is to create the small arcs correctly using maths.

Something like this

path.attr("d", function (d, i) {
    const sx = 0;    
    const sy = height/2;

    //width - total width of chart from subject a to subject b

    const a = width/2;
    //a - distance between subject a and center

    const b = (1.5-i)*distanceBetween;
    //b - distance between trait 1 and trait 2 (between the dots)

    const c = Math.sqrt(a * a + b * b);
    //c - is the diagonal distance between subject a and trait 1

    const angle=Math.atan(a/b);
    //angle - between group to subject a

    const r=1/2*c/Math.cos(angle);
    //r - 1/2 the distance of c -- divided by cos of angle -- will create a radius to draw the arc


    //also equals c/b*(c/2)
//    const r=c/b*(c/2);
    return `M${sx},${sy} A${r},${r} 0 0,${b>0?1:0} ${width},${height/2}`;
});

解决方案

//latest js fiddle - stable with control for all paths in place - based on blackmiaool's answer.

http://jsfiddle.net/rbLk2fbe/2/

 var w = 600;
 var h = 600;


 var data = [{
   "userName": "You",
   "userImage": "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcSTzjaQlkAJswpiRZByvgsb3CVrfNNLLwjFHMrkZ_bzdPOWdxDE2Q"
 }, {
   "userName": "Johnny",
   "userImage": "https://crossovercomicblog.files.wordpress.com/2012/08/johnny-depp-sexy.jpg"
 }, {
   "userName": "Jeri",
   "userImage": "https://68.media.tumblr.com/avatar_3b6d6241698f_128.png"
 }, {
   "userName": "Charlize",
   "userImage": "https://cdn.imza.com/indir/logo/128/charlize-theron.png"
 },{
   "userName": "Charlize",
   "userImage": "https://cdn.imza.com/indir/logo/128/charlize-theron.png"
 },{
   "userName": "Charlize",
   "userImage": "https://cdn.imza.com/indir/logo/128/charlize-theron.png"
 },{
   "userName": "Charlize",
   "userImage": "https://cdn.imza.com/indir/logo/128/charlize-theron.png"
 },{
   "userName": "Angelina",
   "userImage": "https://pbs.twimg.com/profile_images/713650489032908800/nO1dMt6M_400x400.jpg"
 },  {
   "userName": "Them",
   "userImage": "https://68.media.tumblr.com/avatar_8f199caf2d82_128.png"
 }];

 var viz = d3.select("#viz")
   .append("svg")
   .attr("width", w)
   .attr("height", h)
   .append("g")
   .attr("transform", "translate(40,100)");


 var patternsSvg = viz.append('g')
   .attr('class', 'patterns');

 var labelholder = viz.append("g")
   .attr("class", "labelholder");

 var treeholder = viz.append("g")
   .attr("class", "treeholder");

 var userholder = viz.append("g")
   .attr("class", "userholder");



 var smallRadius = 20;
 var bigRadius = 30;

 var smallX = smallRadius + (bigRadius/2);
 var bigX = (bigRadius*2) + (smallRadius/2);

 var verticalGap = (bigRadius * 2) - 5;

 var count = data.length;


 var extendedY = (count-2 * (smallRadius*2)) + ((bigRadius*2) * 2);
 var arcRadiusLeft = (bigRadius / 2);
 var arcRadiusRight = -(bigRadius / 2);


 $.each(data, function(index, value) {
   var defs = patternsSvg.append('svg:defs');

   //big design   
   defs.append('svg:pattern')
     .attr('id', index + "--" + value.userName.toLowerCase())
     .attr('width', 1)
     .attr('height', 1)
     .append('svg:image')
     .attr('xlink:href', value.userImage)
     .attr('x', 0)
     .attr('y', 0)
     .attr('width', bigRadius * 2)
     .attr('height', bigRadius * 2);

   //small design
   defs.append('svg:pattern')
     .attr('id', index + "-" + value.userName.toLowerCase())
     .attr('width', 1)
     .attr('height', 1)
     .append('svg:image')
     .attr('xlink:href', value.userImage)
     .attr('x', 0)
     .attr('y', 0)
     .attr('width', smallRadius * 2)
     .attr('height', smallRadius * 2);

 });



 //plot people circles
 var circle = userholder.append("g").selectAll("circle")
   .data(data);

 circle
   .enter()
   .append("svg:circle")
   .attr("id", function(d) {
     return d.userName.toLowerCase();
   })
   .attr("r", function(d, i) {
     var rad = smallRadius;

     //first and last items -- so you and them
     if (i == 0 || i == count - 1) {
       rad = bigRadius;
     }
     return rad;
   })
   .attr("cx", function(d, i) {
     var cx;
     if (i == 0) {
       cx = 0; //first one 
     } else if (i == count - 1) {
       cx = bigX; //last one
     } else {
       cx = smallX; //small ones
     }
     return cx;
   })
   .attr("cy", function(d, i) {
     var cy;
     if (i == 0) {
       cy = 0;
     } else if (i == count - 1) {
       cy = verticalGap * (i-1) + extendedY + bigRadius;
     } else {
       cy = verticalGap * i
     }
     return cy;
   })
   .style("fill", function(d, i) {
     var id = i + "-" + d.userName.toLowerCase(); //small circles

     //large circles
     if (i == 0 || i == count - 1) {
       id = i + "--" + d.userName.toLowerCase();
     }
     return "url(#" + id + ")";
   });
 //plot people circles



 //__labels  
 var labelholder = d3.select(".labelholder");

 //__ enter
 var labels = labelholder.selectAll("text")
   .data(data);

 labels.enter()
   .append("text")
   .attr("text-anchor", "left")

 //__ update            
 labels
   .attr("x", function(d, i) {

     var displacement = (bigRadius/2) + smallRadius;
     var cx = (smallRadius * 2);
     if (i == 0) {
       cx = bigRadius;
       displacement = bigRadius/2;
     }
     if (i == count - 1) {
       cx = (bigRadius * 2) + bigRadius;
       displacement = bigRadius;
     }

     cx += displacement;

     return cx;
   })
   .attr("y", function(d, i) {
     var cy = verticalGap * i;
     if (i == count - 1) {
       cy += extendedY - (bigRadius/2);
     }
     return cy;
   })
   .text(function(d) {
     return d.userName;
   });
 //__labels


 var backbone = treeholder.append("g")
   .append("svg:path");

 backbone.attr("d", function(d, i) {
   var sx = (bigRadius / 2) - (bigRadius / 2);
   var tx = (bigRadius / 2) - (bigRadius / 2);

   var r = smallRadius;
   if (i == 0 || i == count - 1) {
     r = bigRadius;
   }

   var sy = ((r / 2) * i) + (r);
   var ty = verticalGap * (count - 2) - arcRadiusLeft;
   var dr = 0;

   return "M" + sx + "," + sy + "A" + dr + "," + dr + " 0 0,1 " + tx + "," + ty;
 });

var displaceYBackboneRight = (bigRadius / 2) + 5; 

 var backbone = treeholder.append("g")
   .append("svg:path");

 backbone.attr("d", function(d, i) {
   var sx = (bigRadius * 2) + smallRadius/2;
   var tx = (bigRadius * 2) + smallRadius/2;

   var r = smallRadius;
   if (i == 0 || i == count - 1) {
     r = bigRadius;
   }

   var sy = ((r / 2) * i) + (r) + smallRadius + displaceYBackboneRight;

   var ty = verticalGap * (count - 2) + extendedY;

   var dr = 0;

   return "M" + sx + "," + sy + "A" + dr + "," + dr + " 0 0,1 " + tx + "," + ty;
 });


 //branches on the left 
 var leftpath = treeholder.append("g").selectAll("path.leftpath")
   .data(data)

 leftpath
   .enter().append("svg:path")
   .attr("class", function(d) {
     return "leftpath";
   });

 leftpath.attr("d", function(d, i) {
   var sx = 0;
   var tx = arcRadiusLeft;

   var sy = verticalGap * i - arcRadiusLeft;
   var ty = verticalGap * i;

   if (i != 0 && i != count - 1) {
     return "M" + sx + "," + sy + "A" + arcRadiusLeft + "," + arcRadiusLeft + " 0 0,0 " + tx + "," + ty;
   }

 });




 //branches on the left 
 var rightpath = treeholder.append("g").selectAll("path.rightpath")
   .data(data)

 rightpath
   .enter().append("svg:path")
   .attr("class", function(d) {
     return "rightpath";
   });

 rightpath.attr("d", function(d, i) {
   var sx = (bigRadius*2) + (smallRadius/2);
   var tx = arcRadiusRight + (bigRadius*2) + (smallRadius/2);

   var sy = verticalGap * i + (bigRadius / 2);
   var ty = verticalGap * i + arcRadiusRight + (bigRadius / 2);

   if (i != 0 && i != count - 1) {
     return "M" + sx + "," + sy + "A" + arcRadiusLeft + "," + arcRadiusLeft + " 0 0,0 " + tx + "," + ty;
   }


 });

这篇关于d3.js网络曲线路径控制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆