鼠标悬停时更改链接和箭头颜色

时间:2018-02-08 23:10:59

标签: javascript d3.js svg colors mouseover

我已经针对这个问题尝试了很多解决方案,但我无法想象如何做到这一点......

我的目标是在鼠标悬停此节点时更改连接到节点的链接箭头的颜色。

<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style type="text/css">
        .node { font: 12px sans-serif;}

        .link { stroke: black; stroke-opacity: .4; stroke-width: 2px; }
    </style>
</head>
<body>
<svg width="1500" height="1000"></svg>

<script src="http://d3js.org/d3.v4.min.js" type="text/javascript"></script>
<script src="http://d3js.org/d3-selection-multi.v1.js"></script>

<script type="text/javascript">
    var colors = d3.scaleOrdinal(d3.schemeCategory20);

    var svg = d3.select("svg"),
        width = +svg.attr("width"),
        height = +svg.attr("height"),
        node,
        link;

    svg.append('defs').append('marker')
        .attrs({'id':'arrowhead',
            'viewBox':'-0 -5 10 10',
            'refX':15,
            'refY':0,
            'orient':'auto',
            'markerWidth':6,
            'markerHeight':6,
            'xoverflow':'visible'})
        .append('svg:path')
        .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
        .style('fill', 'black')
        .style('stroke', 'black');

    var simulation = d3.forceSimulation()
        .force("link", d3.forceLink().id(function (d) {return d.id;}).distance(500).strength(1))
        .force("charge", d3.forceManyBody())
        .force("center", d3.forceCenter(width / 2, height / 2));


    var jsonstring = '{"nodes": [{"name": "25", "id": "25"},{"name": "16", "id": "16"},{"name": "12", "id": "12"},{"name": "20", "id": "20"},{"name": "21", "id": "21"},{"name": "9", "id": "9"},{"name": "24", "id": "24"},{"name": "5", "id": "5"},{"name": "23", "id": "23"},{"name": "13", "id": "13"},{"name": "14", "id": "14"},{"name": "15", "id": "15"},{"name": "18", "id": "18"},{"name": "2", "id": "2"},{"name": "3", "id": "3"},{"name": "4", "id": "4"},{"name": "6", "id": "6"},{"name": "7", "id": "7"},{"name": "10", "id": "10"},{"name": "11", "id": "11"},{"name": "1", "id": "1"},{"name": "22", "id": "22"},{"name": "17", "id": "17"},{"name": "19", "id": "19"},{"name": "8", "id": "8"}],"links": [{"source": "25", "target": "16"},{"source": "25", "target": "12"},{"source": "25", "target": "20"},{"source": "25", "target": "21"},{"source": "25", "target": "9"},{"source": "25", "target": "24"},{"source": "25", "target": "12"},{"source": "16", "target": "16"},{"source": "16", "target": "12"},{"source": "16", "target": "12"},{"source": "12", "target": "16"},{"source": "12", "target": "12"},{"source": "12", "target": "5"},{"source": "12", "target": "12"},{"source": "20", "target": "16"},{"source": "20", "target": "12"},{"source": "20", "target": "23"},{"source": "20", "target": "13"},{"source": "20", "target": "14"},{"source": "20", "target": "5"},{"source": "20", "target": "15"},{"source": "20", "target": "12"},{"source": "21", "target": "16"},{"source": "21", "target": "12"},{"source": "21", "target": "15"},{"source": "21", "target": "13"},{"source": "21", "target": "18"},{"source": "21", "target": "2"},{"source": "21", "target": "12"},{"source": "9", "target": "16"},{"source": "9", "target": "12"},{"source": "9", "target": "23"},{"source": "9", "target": "21"},{"source": "9", "target": "13"},{"source": "9", "target": "3"},{"source": "9", "target": "12"},{"source": "24", "target": "16"},{"source": "24", "target": "12"},{"source": "24", "target": "23"},{"source": "24", "target": "18"},{"source": "24", "target": "4"},{"source": "24", "target": "6"},{"source": "24", "target": "7"},{"source": "24", "target": "12"},{"source": "5", "target": "16"},{"source": "5", "target": "12"},{"source": "5", "target": "12"},{"source": "5", "target": "4"},{"source": "5", "target": "15"},{"source": "5", "target": "10"},{"source": "5", "target": "12"},{"source": "23", "target": "16"},{"source": "23", "target": "12"},{"source": "23", "target": "6"},{"source": "23", "target": "10"},{"source": "23", "target": "12"},{"source": "13", "target": "16"},{"source": "13", "target": "12"},{"source": "13", "target": "20"},{"source": "13", "target": "10"},{"source": "13", "target": "14"},{"source": "13", "target": "5"},{"source": "13", "target": "11"},{"source": "13", "target": "1"},{"source": "13", "target": "16"},{"source": "13", "target": "12"},{"source": "14", "target": "16"},{"source": "14", "target": "12"},{"source": "14", "target": "2"},{"source": "14", "target": "13"},{"source": "14", "target": "4"},{"source": "14", "target": "5"},{"source": "14", "target": "12"},{"source": "15", "target": "16"},{"source": "15", "target": "12"},{"source": "15", "target": "6"},{"source": "15", "target": "10"},{"source": "15", "target": "22"},{"source": "15", "target": "20"},{"source": "15", "target": "12"},{"source": "18", "target": "16"},{"source": "18", "target": "12"},{"source": "18", "target": "2"},{"source": "18", "target": "12"},{"source": "2", "target": "16"},{"source": "2", "target": "12"},{"source": "2", "target": "13"},{"source": "2", "target": "17"},{"source": "2", "target": "12"},{"source": "2", "target": "11"},{"source": "2", "target": "12"},{"source": "3", "target": "16"},{"source": "3", "target": "12"},{"source": "3", "target": "16"},{"source": "3", "target": "18"},{"source": "3", "target": "10"},{"source": "3", "target": "12"},{"source": "4", "target": "16"},{"source": "4", "target": "12"},{"source": "4", "target": "14"},{"source": "4", "target": "5"},{"source": "4", "target": "13"},{"source": "4", "target": "10"},{"source": "4", "target": "12"},{"source": "4", "target": "12"},{"source": "6", "target": "16"},{"source": "6", "target": "12"},{"source": "6", "target": "20"},{"source": "6", "target": "13"},{"source": "6", "target": "3"},{"source": "6", "target": "19"},{"source": "6", "target": "12"},{"source": "7", "target": "16"},{"source": "7", "target": "12"},{"source": "7", "target": "20"},{"source": "7", "target": "21"},{"source": "7", "target": "12"},{"source": "7", "target": "8"},{"source": "7", "target": "9"},{"source": "7", "target": "11"},{"source": "7", "target": "12"},{"source": "10", "target": "16"},{"source": "10", "target": "12"},{"source": "10", "target": "1"},{"source": "10", "target": "5"},{"source": "10", "target": "17"},{"source": "10", "target": "22"},{"source": "10", "target": "16"},{"source": "10", "target": "4"},{"source": "10", "target": "13"},{"source": "10", "target": "12"},{"source": "11", "target": "16"},{"source": "11", "target": "12"},{"source": "11", "target": "7"},{"source": "11", "target": "3"},{"source": "11", "target": "12"},{"source": "11", "target": "22"},{"source": "11", "target": "12"},{"source": "1", "target": "16"},{"source": "1", "target": "12"},{"source": "1", "target": "16"},{"source": "1", "target": "22"},{"source": "1", "target": "9"},{"source": "1", "target": "15"},{"source": "1", "target": "12"},{"source": "22", "target": "16"},{"source": "22", "target": "12"},{"source": "22", "target": "5"},{"source": "22", "target": "2"},{"source": "22", "target": "17"},{"source": "22", "target": "12"},{"source": "22", "target": "8"},{"source": "22", "target": "12"},{"source": "19", "target": "16"},{"source": "19", "target": "12"},{"source": "19", "target": "24"},{"source": "19", "target": "15"},{"source": "19", "target": "16"},{"source": "19", "target": "23"},{"source": "19", "target": "12"},{"source": "8", "target": "16"},{"source": "8", "target": "12"},{"source": "8", "target": "20"},{"source": "8", "target": "15"},{"source": "8", "target": "12"},{"source": "8", "target": "12"}]}';

    var graph=JSON.parse(jsonstring);

    //d3.json("graph.json", function (error, graph) {
        //if (error) throw error;
        update(graph.links, graph.nodes);
    //})

    function update(links, nodes) {
        link = svg.selectAll(".link")
            .data(links)
            .enter()
            .append("line")
            .attr("class", "link")
            .attr('marker-end','url(#arrowhead)')

        link.append("title")
            .text(function (d) {return d.type;});

        edgepaths = svg.selectAll(".edgepath")
            .data(links)
            .enter()
            .append('path')
            .attrs({
                'class': 'edgepath',
                'fill-opacity': 0,
                'stroke-opacity': 0,
                'id': function (d, i) {return 'edgepath' + i}
            })
            .style("pointer-events", "none");

        edgelabels = svg.selectAll(".edgelabel")
            .data(links)
            .enter()
            .append('text')
            .style("pointer-events", "none")
            .attrs({
                'class': 'edgelabel',
                'id': function (d, i) {return 'edgelabel' + i},
                'font-size': 10,
                'fill': '#aaa'
            });

        edgelabels.append('textPath')
            .attr('xlink:href', function (d, i) {return '#edgepath' + i})
            .style("text-anchor", "middle")
            .style("pointer-events", "none")
            .attr("startOffset", "50%")
            .text(function (d) {return d.type});

        node = svg.selectAll(".node")
            .data(nodes)
            .enter()
            .append("g")
            .attr("class", "node")
            .call(d3.drag()
                    .on("start", dragstarted)
                    .on("drag", dragged)
                    //.on("end", dragended)
            );

        node.append("circle")
            .attr("r", 8)
            .style("fill", function (d, i) {return colors(i);})

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

        node.append("text")
            .attr("dy", -4)
            .attr("dx", 10)
            .text(function (d) {return d.name;});

        simulation
            .nodes(nodes)
            .on("tick", ticked);

        simulation.force("link")
            .links(links);
    }

    function ticked() {
        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("transform", function (d) {return "translate(" + d.x + ", " + d.y + ")";});

        edgepaths.attr('d', function (d) {
            return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
        });

        edgelabels.attr('transform', function (d) {
            if (d.target.x < d.source.x) {
                var bbox = this.getBBox();

                rx = bbox.x + bbox.width / 2;
                ry = bbox.y + bbox.height / 2;
                return 'rotate(180 ' + rx + ' ' + ry + ')';
            }
            else {
                return 'rotate(0)';
            }
        });
    }

    function dragstarted(d) {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart()
        d.fx = d.x;
        d.fy = d.y;
    }

    function dragged(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
    }

    // On node hover, examine the links to see if their
// source or target properties match the hovered node.
node.on('mouseover', function(d) {
  link.style('stroke', function(l) {
    if (d === l.source || d === l.target)
      return "red";
    else
      return "black";
    });

});

// Set the stroke width back to normal when mouse leaves the node.
node.on('mouseout', function() {
  link.style('stroke', "black");
});

//    function dragended(d) {
//        if (!d3.event.active) simulation.alphaTarget(0);
//        d.fx = undefined;
//        d.fy = undefined;
//    }

</script>

</body>
</html>

目前,我实现了更改链接颜色,但我也无法弄清楚如何更改箭头。我注意到在悬停时更改 stroke-width 会影响链接和箭头,但更改任何其他属性(fill,stroke ...)只会影响链接。

也许答案很明显,但我在JS中很新。 有帮助吗?

1 个答案:

答案 0 :(得分:2)

mouseover回调中选择标记并更改其样式。此外,命名你的选择是一个好主意。

这是一个非常基本的演示,请注意mouseover事件(以及mouseout)我正在改变路径和标记样式:

var svg = d3.select("svg");
var defs = svg.append("defs");

var marker = defs.append("marker")
  .attr("id", "marker")
  .attr("viewBox", "0 -5 10 10")
  .attr("refX", 0)
  .attr("refY", 0)
  .attr("markerWidth", 30)
  .attr("markerHeight", 30)
  .attr("orient", "auto")
  .attr("markerUnits", "userSpaceOnUse")
  .append("path")
  .attr("d", "M0,-5L10,0L0,5")
  .style("fill", "firebrick");

var path = svg.append("path")
  .attr("d", "M50,50 L250,50")
  .style("stroke", "firebrick")
  .style("stroke-width", "8px")
  .attr("marker-end", "url(#marker)");

path.on("mouseover", function() {
  d3.select(this).style("stroke", "blue");
  marker.style("fill", "blue");
}).on("mouseout", function() {
  d3.select(this).style("stroke", "firebrick")
  marker.style("fill", "firebrick");
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>