将箭头颜色与 D3 中的线条颜色匹配 [英] Match Arrowhead Color to Line Color in D3

查看:25
本文介绍了将箭头颜色与 D3 中的线条颜色匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试让我的有向图链接的箭头颜色与边缘颜色相匹配.令人惊讶的是,我还没有找到完整的解决方案,尽管

这种工作方式是有很多不同的标记,每个标记都定义了标记的颜色.这是定义的所有标记的屏幕截图:

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

我已经修改了您的示例,为每个路径添加了一个新的 marker(并稍微更改了渐变中的颜色以证明它正在工作).这是我所拥有的:

var width = 960,高度 = 500;var 颜色 = d3.scale.category20();var gradientColor = d3.scale.linear().domain([0, 15]).range(["#ff0000", "#0000ff"]);var force = d3.layout.force().linkDistance(10).linkStrength(2).size([宽度, 高度]);var svg = d3.select("body").append("svg").attr("宽度", 宽度).attr("高度", 高度);var defs = svg.append("svg:defs");d3.json(http://bost.ocks.org/mike/miserables/miserables.json",函数(错误,图){如果(错误)抛出错误;功能标记(颜色){defs.append("svg:marker").attr("id", color.replace("#", "")).attr("viewBox", "0 -5 10 10").attr("refX", 15)//这设置它坐多远,有点.attr("refY", 0).attr("markerWidth", 9).attr("markerHeight", 9).attr(东方",自动").attr("markerUnits", "userSpaceOnUse").append("svg:path").attr("d", "M0,-5L10,0L0,5").style("填充", 颜色);返回网址("+颜色+)";};var 节点 = graph.nodes.slice(),链接 = [],双链接 = [];graph.links.forEach(函数(链接){var s = 节点 [link.source],t = 节点[链接.目标],i = {},//中间节点linkValue = link.value//用于将值从链接传输到双链接;节点推(i);链接.推送({来源:s,目标:我}, {来源:我,目标:t});bilinks.push([s, i, t, linkValue]);});force.nodes(节点).links(链接).开始();var link = svg.selectAll(".link").data(bilinks).enter().append("path").attr(类",链接").style("填充", "无").style("不透明度", "0.5").style("笔画宽度", "2").each(function(d) {var color = gradientColor(d[3]);控制台日志(d [3]);d3.select(this).style("stroke", color).attr("标记结束", 标记(颜色));});var node = svg.selectAll(".node").data(graph.nodes).enter().append("g").attr(类",节点").call(force.drag);node.append("圆圈").attr("r", 函数 (d) {返回 2 + d.group;}).style("不透明度", 0.5).style(填充",功能(d){返回颜色(d.group);});node.append("title").text(功能(d){返回 d.name;});force.on("tick", function () {链接.attr(d",函数(d){返回 "M" + d[0].x + "," + d[0].y + "S" + d[1].x + "," + d[1].y + " " + d[2].x + "," + d[2].y;});node.attr(转换",函数(d){返回 "translate(" + d.x + "," + d.y + ")";});});});

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

I am trying to do the obvious thing of getting the arrowhead colors of my directed graph's links to match the edge colors. Surprisingly I have not found a complete solution for doing this, although this older post seems like an excellent starting point. I would be fine with adapting that solution to work as outlined below, or if there is a superior method for creating arrowheads that achieves this effect I would be most thankful.

First, I have a linear gradient color function to color my edges by property like this:

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

Then, like that previous post I have a function for adding markers:

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 + ")";    };

And then the links definition I have is this one based on the 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" ) );

This DOES NOT work as written; the browser gives me an "Uncaught TypeError: Cannot read property '5' of undefined" (where 'd[5]' refers to the fifth property in a list of properties that the links have). The problem is clearly passing the data function to the marker function in this case. If I feed in a static color like "#FFCC33" then the arrowheads DO change color (now). Unfortunately the person who posted this "marker function" solution 1.5 years ago didn't include the bit about passing the color to the marker function at all.

I don't know how to feed in the link's color properly. Ideally I would be able to use a reference to the color of the link that the arrowhead is attached to rather than inputting the same color function (because eventually I'm going to be coloring the links via different schemes based on button presses).

I've created a JS Fiddle that includes all the necessary bits to see and solve the problem. Currently I'm passing a static color to the markers, but it should be whatever is the color of the link it is attached to. I've also included features for another question on properly positioning the arrowheads and edge tails.

解决方案

I don't believe you're able to define a single SVG marker and change it's colour. Instead you need to define the marker many times (1 for each colour that you need to use). There's a nice example that recently popped up onto the D3 website.

The way this works, is by having lots if different markers, each defining the colour of the marker. Here's a screenshot of all the markers that are defined:

Then this particular example, cycles the CSS classes on the paths. The particular colored marker that each path is using is defined within the CSS class that's being applied to a path at any given time.

I've modified your example to add a new marker per path (and changed the colors slightly in the gradient to prove that it's working). Here's what I've got:

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>

这篇关于将箭头颜色与 D3 中的线条颜色匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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