2016-02-05 155 views
2

之间的渐变线这是我的D3力布局: (请运行该代码段)D3js力布局 - 与节点

var width = 600, 
 
    height = 600; 
 

 
var svg = d3.select('body').append('svg') 
 
    .attr('width', width) 
 
    .attr('height', height); 
 

 
var color = d3.scale.category20(); 
 

 
var dataNodes = [ 
 
    { x: width/3, y: height/3 , group: 0, color: 'blue'}, 
 
    { x: 2*width/3, y: height/3, group: 1, color: 'red' }, 
 
    { x: width/2, y: 2*height/3, group: 2, color: 'green'} 
 
]; 
 

 
var dataLinks = [ 
 
    { source: 0, target: 1}, 
 
    { source: 1, target: 2}, 
 
    { source: 2, target: 0} 
 
]; 
 

 
var force = d3.layout.force() 
 
    .charge(-400) 
 
    .linkDistance(height/2) 
 
    .size([width, height]) 
 
    .linkStrength(1.3) 
 
    .friction(0.8) 
 
    .gravity(0.9); 
 

 
force 
 
    .nodes(dataNodes) 
 
    .links(dataLinks) 
 
    .start(); 
 

 
var link = svg.selectAll(".link") 
 
     .data(dataLinks) 
 
    .enter().append("line") 
 
     .attr("class", "link"); 
 

 
var node = svg.selectAll(".node") 
 
    .data(dataNodes) 
 
    .enter().append("circle") 
 
    .attr("class", function(d){ return "node " + d.color}) 
 
    .attr("r", width/20) 
 
    .call(force.drag); 
 

 
node.append("title") 
 
     .text(function(d) { return d.color; }); 
 

 

 
force.on('tick', function() { 
 
    link.attr("x1", function(d) { return d.source.x; }) 
 
     .attr("y1", function(d) { return d.source.y; }) 
 
     .attr("x2", function(d) { return d.target.x; }) 
 
     .attr("y2", function(d) { return d.target.y; }); 
 

 
    node.attr("cx", function(d) { return d.x; }) 
 
     .attr("cy", function(d) { return d.y; }); 
 
});
.node { 
 
    fill: #ccc; 
 
    stroke: #fff; 
 
    stroke-width: 0; 
 
} 
 
.node.blue { 
 
    fill: blue; 
 
} 
 
.node.red { 
 
    fill: red; 
 
} 
 
.node.green { 
 
    fill: green; 
 
} 
 

 
.link { 
 
    fill: none;   
 
    stroke: black; 
 
    stroke-width: 20px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

这就是我想要实现: enter image description here

这怎么可能?我如何在节点之间的链接上应用渐变? 如果有什么不明确的地方,请询问。

谢谢!

+0

我不知道你是否已经解决了这个问题,但我今天遇到了同样的问题,我认为它有正确的代码。在下面检查我的答案。 – echonax

回答

2

你可以做这样的事情,并创建梯度并通过梯度作为ID:

var link = svg.selectAll(".link") 
     .data(dataLinks) 
    .enter().append("line") 
     .attr("class", "link") 
     .style("stroke",function(d){ 
      var id = "S"+d.source.index +"T" + d.target.index; 
      var gradient1 = defs.append("linearGradient").attr("id", id); 
      gradient1.append("stop").attr("offset", "0%").attr("stop-color", d.target.color); 
      gradient1.append("stop").attr("offset", "100%").attr("stop-color", d.source.color); 
      return "url(#" + id + ")"; 
     }); 

工作代码here

希望这有助于!

+0

当你转动节点时,梯度似乎没有正确更新 – ee2Dev

+0

感谢您的回答。但是有时候梯度的“方向”与ee2Dev提到的节点的位置没有关系。有没有办法在转动节点时改变梯度的方向? – Mangocrack

+0

感谢您指出...是的,在拖动节点的梯度正在重置... sry无法修复它.. – Cyril

1

这里的结果:https://jsfiddle.net/tekh27my/11/

定义部分几乎是相同与@西里尔

var gradient = d3.select("svg").append("defs") 
    .append("linearGradient") 
    .attr("id", "gradient") 
    .attr("spreadMethod", "pad"); 
    //start color white 
    gradient.append("stop") 
    .attr("offset", "0%") 
    .attr("stop-color", "red") 
    .attr("stop-opacity", 1); 
    //end color steel blue 
    gradient.append("stop") 
    .attr("offset", "100%") 
    .attr("stop-color", "green") 
    .attr("stop-opacity", 1); 

但在每个标记需要有在X1,Y1和X2动态更新,Y2

所以这是 “嘀” 函数的代码:

var linkVector = new Vector2(d.target.x-d.source.x,d.target.y-d.source.y).getUnitVector(); 
var perpVector = linkVector.perpendicularClockwise().scale(radius); 
var gradientVector = linkVector.scale(0.5); 


gradient 
    .attr("x1", 0.5-gradientVector.X) 
    .attr("y1", 0.5-gradientVector.Y) 
    .attr("x2", 0.5+gradientVector.X) 
    .attr("y2", 0.5+gradientVector.Y); 

0.5是路径的中间部分(你可以猜到),因为根据我的计算,这些是单位向量。

gradientVector是一个缩放到0.5的单位向量。

而这里的单位向量计算代码:

var Vector2 = function(x,y) { 
    this.magnitude = Math.sqrt(x*x+y*y); 
    this.X = x; 
    this.Y = y; 
}; 

Vector2.prototype.perpendicularClockwise = function(){ 
    return new Vector2(-this.Y, this.X); 
}; 

Vector2.prototype.perpendicularCounterClockwise = function(){ 
    return new Vector2(this.Y, -this.X); 
}; 

Vector2.prototype.getUnitVector = function(){ 
    return new Vector2(this.X/this.magnitude, this.Y/this.magnitude); 
}; 

Vector2.prototype.scale = function(ratio){ 
    return new Vector2(ratio*this.X, ratio*this.Y); 
}; 

注:sourceDelta/targetDelta计算“滴”里面的路径是无关这个问题。