且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

将箭头颜色与 D3 中的线条颜色匹配

更新时间:2022-10-14 22:17:31

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>