2015-10-06 178 views
2

我正在尝试做一些明显的事情,让我的有向图形链接的箭头颜色与边缘颜色相匹配。令人惊讶的是,我还没有找到一个完整的解决方案,虽然this older post似乎是一个很好的起点。如果适应该解决方案的工作方式如下所述,或者如果有创建达到这种效果的箭头的更好方法,我会非常感激。将箭头颜色与D3中的线条颜色相匹配

首先,我有一个线性渐变色功能的属性这样上色我的边缘:

var gradientColor = d3.scale.linear().domain([0,1]).range(["#08519c","#bdd7e7"]); 

然后,像以前的文章中,我有添加标记功能:

function marker (color) { 
    var reference; 
    svg.append("svg:defs").selectAll("marker") 
    .data([reference]) 
    .enter().append("svg:marker")  
    .attr("id", String) 
    .attr("viewBox", "0 -5 10 10") 
    .attr("refX", 15) // This sets how far back it sits, kinda 
    .attr("refY", 0) 
    .attr("markerWidth", 9) 
    .attr("markerHeight", 9) 
    .attr("orient", "auto") 
    .attr("markerUnits", "userSpaceOnUse") 
    .append("svg:path") 
    .attr("d", "M0,-5L10,0L0,5") 
    .style("fill", color); 
    return "url(#" + reference + ")"; }; 

然后我的链接定义是基于Curved Links example的这一个。

var link = svg.selectAll(".link") 
    .data(bilinks) 
    .enter().append("path") 
    .attr("class", "link") 
    .style("fill", "none") 
    .style("opacity", "0.5")  
    .style("stroke-width", "2") 
    .style("stroke", function(d) { return gradientColor(d[3]); }) 
    .attr("marker-end", marker("#FFCC33")); 

这不会写作;浏览器给我一个“Uncaught TypeError:无法读取未定义的属性'5'(其中'd [5]'指的是链接所具有的属性列表中的第五个属性)。在这种情况下,问题显然是将数据函数传递给标记函数。如果我像“#FFCC33”那样输入静态颜色,那么箭头会改变颜色(现在)。不幸的是,1.5年前发布这种“标记函数”解决方案的人并没有将颜色传递给标记函数。

我不知道如何正确喂食链接的颜色。理想情况下,我将能够使用对箭头所连接的链接的颜色的引用,而不是输入相同的颜色函数(因为最终我将通过基于按钮按压的不同方案来着色链接)。

我创建了一个JS Fiddle,其中包含了查看和解决问题所需的所有位。目前,我将静态颜色传递给标记,但它应该是连接到它的链接的颜色。我还包含了关于正确定位箭头和边缘尾部的另一个问题的功能。

+0

这让我奇怪,为什么老回答您链接到有任何upvotes可言。虽然这个想法可能是正确的,但是代码不会出于某些原因:1. val不会被分配任何值,所以返回值将是'“url(#undefined)”; 2.“id”将始终是一个空字符串; 3.当将函数'marker()'传递给'attr()'时,参数丢失。要获得有关此代码适配的帮助,建立一个可用的示例可以很有帮助。 – altocumulus

回答

2

我不相信你能够定义一个单一的SVG标记并改变它的颜色。相反,您需要多次定义标记(每种颜色需要使用1个)。有一个很好的example,最近弹出到D3网站。

enter image description here

这种工作方式,是由具有许多不同,如果标记,每个定义标记的颜色。以下是定义的所有标记的屏幕截图:

enter image description here

然后该特定示例中,循环路径上的CSS类。每个路径使用的特定颜色标记都是在任何给定时间应用于路径的CSS类中定义的。

我修改了您的示例,为每个路径添加了一个新的(并在渐变中略微更改颜色以证明它正在工作)。下面是我得到了什么:

var width = 960, 
 
    height = 500; 
 

 
var color = d3.scale.category20(); 
 
var gradientColor = d3.scale.linear().domain([0, 15]).range(["#ff0000", "#0000ff"]); 
 

 
var force = d3.layout.force() 
 
    .linkDistance(10) 
 
    .linkStrength(2) 
 
    .size([width, height]); 
 

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

 
var defs = svg.append("svg:defs"); 
 

 
d3.json("http://bost.ocks.org/mike/miserables/miserables.json", function (error, graph) { 
 
    if (error) throw error; 
 

 

 
    function marker(color) { 
 

 
     defs.append("svg:marker") 
 
      .attr("id", color.replace("#", "")) 
 
      .attr("viewBox", "0 -5 10 10") 
 
      .attr("refX", 15) // This sets how far back it sits, kinda 
 
      .attr("refY", 0) 
 
      .attr("markerWidth", 9) 
 
      .attr("markerHeight", 9) 
 
      .attr("orient", "auto") 
 
      .attr("markerUnits", "userSpaceOnUse") 
 
      .append("svg:path") 
 
      .attr("d", "M0,-5L10,0L0,5") 
 
      .style("fill", color); 
 
     
 
     return "url(" + color + ")"; 
 
    }; 
 

 
    var nodes = graph.nodes.slice(), 
 
     links = [], 
 
     bilinks = []; 
 

 
    graph.links.forEach(function (link) { 
 
     var s = nodes[link.source], 
 
      t = nodes[link.target], 
 
      i = {}, // intermediate node 
 
      linkValue = link.value // for transfering value from the links to the bilinks 
 
      ; 
 
     nodes.push(i); 
 
     links.push({ 
 
      source: s, 
 
      target: i 
 
     }, { 
 
      source: i, 
 
      target: t 
 
     }); 
 
     bilinks.push([s, i, t, linkValue]); 
 
    }); 
 

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

 
    var link = svg.selectAll(".link") 
 
     .data(bilinks).enter().append("path") 
 
     .attr("class", "link") 
 
     .style("fill", "none") 
 
     .style("opacity", "0.5") 
 
     .style("stroke-width", "2") 
 
     .each(function(d) { 
 
      var color = gradientColor(d[3]); 
 
      console.log(d[3]); 
 
      d3.select(this).style("stroke", color) 
 
          .attr("marker-end", marker(color)); 
 
     }); 
 

 
    var node = svg.selectAll(".node") 
 
     .data(graph.nodes) 
 
     .enter().append("g") 
 
     .attr("class", "node") 
 
     .call(force.drag); 
 

 
    node.append("circle") 
 
     .attr("r", function (d) { 
 
     return 2 + d.group; 
 
    }) 
 
     .style("opacity", 0.5) 
 
     .style("fill", function (d) { 
 
     return color(d.group); 
 
    }); 
 

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

 
    force.on("tick", function() { 
 
     link.attr("d", function (d) { 
 
      return "M" + d[0].x + "," + d[0].y + "S" + d[1].x + "," + d[1].y + " " + d[2].x + "," + d[2].y; 
 
     }); 
 
     node.attr("transform", function (d) { 
 
      return "translate(" + d.x + "," + d.y + ")"; 
 
     }); 
 
    }); 
 
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

+0

这很好,因为它既(1)有效,并且(2)微创,因此最大限度地模块化......对于已经以这种方式使用箭头标记的任何人来说,这是一个简单的调整。我创建了一个[更新的JSFiddle](http://jsfiddle.net/AaronBramson/0797gxb2/2/),其中包含您的解决方案并调整了颜色渐变以使更改更清晰。剩下的唯一事情就是让[边和箭头始发并终止于节点边界](http://stackoverflow.com/questions/32966823/links-and-arrowheads-to-terminate-at-borders-of-节点-在-D3)。 –