简体   繁体   中英

how to highlight the selected node in d3js?

I want to highlight the selected node and its connected nodes on clicking any node in d3js, and the other nodes will disappear or gets dull.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="D3js_edges_connected_by_nodes_id.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
    <title>Weighted Citation Graph</title>
    <style>
        path.link {
            fill: none;
            stroke: #666;
            stroke-width: 1.5px;
        }

        circle {
            fill: #ccc;
            stroke: #333;
            stroke-width: 1.5px;
        }

        text {
            font: 10px sans-serif;
            pointer-events: none;
        }

            text.shadow {
                stroke: #fff;
                stroke-width: 3px;
                stroke-opacity: .8;
            }

        body {
            background-color: white;
            margin: 0px;
        }

        .graphContainer {
            text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
        }
    </style>
    <script>
        function load_graph(text) {

            var color = d3.scale.category20();
            //try{
            //    var data = JSON.parse(text);
            //} catch (e) {
            //    window.alert("sometext: "+e);
            //}

            var data = { "nodes": [{ "id": 127230, "name": "Optimization of query evaluation algorithms", "citation": 26, "group": 10 }, { "id": 127254, "name": "Flow algorithms for parallel query optimization", "citation": 22, "group": 10 }, { "id": 127380, "name": "Randomized approximation algorithms for query optimization problems on two processors", "citation": 14, "group": 10 }, { "id": 127438, "name": "Optimization algorithms for simultaneous multidimensional queries in OLAP environments", "citation": 12, "group": 10 }, { "id": 127063, "name": "Query optimization in database systems", "citation": 230, "group": 10 }, { "id": 127158, "name": "Query optimization in a memory-resident domain relational calculus database system", "citation": 41, "group": 10 }, { "id": 129760, "name": "An Overview of TQuel", "citation": 22, "group": 10 }, { "id": 129867, "name": "ADVISORS", "citation": 10, "group": 10 }, { "id": 129872, "name": "Tellabs and THRIP through the Telkom Centre of Excellence at Rhodes University.", "citation": 10, "group": 10 }, { "id": 127412, "name": "Optimal service ordering in decentralized queries over web services", "citation": 13, "group": 10 }, { "id": 130856, "name": "Queries over Web Services", "citation": 10, "group": 10 }, { "id": 130959, "name": "Exploiting Parallelism to Accelerate Keyword Search On Deep-web Sources", "citation": 10, "group": 10 }, { "id": 131199, "name": "Contents lists available at ScienceDirect Future Generation Computer Systems", "citation": 10, "group": 10 }, { "id": 131211, "name": "Flow Algorithms for Parallel Query Optimization", "citation": 10, "group": 10 }, { "id": 127373, "name": "Multi-query Optimization for On-Line Analytical Processing", "citation": 14, "group": 10 }, { "id": 133379, "name": "Concise descriptions of subsets of structured sets", "citation": 21, "group": 10 }], "links": [{ "source": 127230, "target": 127063, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 127158, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 129760, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 129867, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 129872, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 127063, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127230, "target": 127158, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127230, "target": 129760, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127230, "target": 129867, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127230, "target": 129872, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 127412, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 130856, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 130959, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 131199, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 131211, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 127412, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 130856, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 130959, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 131199, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 131211, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127438, "target": 127373, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127438, "target": 133379, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127438, "target": 127373, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127438, "target": 133379, "name": "c1", "value": 10, "grouo": 9 }] };

            // used to store the number of links between two nodes. 
            // mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex;
            var mLinkNum = {};

            // sort links first
            // sortLinks();

            data.links.sort(function (a, b) {
                if (a.source > b.source) { return 1; }
                else if (a.source < b.source) { return -1; }
                else {
                    if (a.target > b.target) { return 1; }
                    if (a.target < b.target) { return -1; }
                    else { return 0; }
                }
            })

            // set up linkIndex and linkNumer, because it may possible multiple links share the same source and target node
            setLinkIndexAndNum();


            var w = 1345,
                h = 1000;

            var force = d3.layout.force()
            .size([w, h])
            .linkDistance(100)
            .charge(-800)
            .on("tick", tick);

            var svg = d3.select(".graphContainer").append("svg:svg")
            .attr("width", w)
            .attr("height", h);

            var color = d3.scale.category10()
            var edges = [];
            data.links.forEach(function (e) {
                var sourceNode = data.nodes.filter(function (n) {
                    return n.id === e.source;
                })[0],
                    targetNode = data.nodes.filter(function (n) {
                        return n.id === e.target;
                    })[0];

                edges.push({
                    source: sourceNode,
                    target: targetNode,
                    name: e.name,
                    value: e.value,
                    linkindex: e.linkindex,
                    grouo: e.grouo
                });
            });

            console.log(edges)
            force
              .nodes(data.nodes)
              .links(edges)
              .start();

            var path = svg.append("svg:g")
            .selectAll("line")
            .data(edges)
            .enter().append("svg:path")
            .attr("class", "link")
            .style("stroke-width", function (d, i) {
                console.log(d.value)
                return Math.sqrt(d.value);
            }).style('stroke', function (d) {
                return color(d.grouo);
            });


            var circle = svg.append("svg:g")
            .selectAll("circle")
            .data(force.nodes())
            .enter().append("svg:circle")
            .attr("r", function (d) {
                return (Math.sqrt(d.citation));
            })
            .style("fill", function (d) {
                return color(d.group);
            })
            .call(force.drag);

            var text = svg.append("svg:g")
            .selectAll("g")
            .data(force.nodes())
            .enter().append("svg:g");
            console.log('test');
            // A copy of the text with a thick white stroke for legibility.
            //text.append("svg:text")
              //.attr("x", 8)
              //.attr("y", ".31em")
              //.attr("class", "shadow")
              //.text(function (d) {
                  //return d.name;
              //});

            text.append("svg:text")
              .attr("x", 8)
              .attr("y", ".31em")
              .text(function (d) {
                 // return d.name;
              });

            // Use elliptical arc path segments to doubly-encode directionality.
            function tick() {
                path.attr("d", function (d, i) {
                    var dx = d.target.x - d.source.x,
                       dy = d.target.y - d.source.y,
                       dr = 30 * d.linkindex;  //linknum is defined above
                    var output = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
                    //console.log(d)
                    return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
                });

                // Add tooltip to the connection path
                path.append("svg:title")
                  .text(function (d, i) {
                      return d.name;
                  });

                circle.attr("transform", function (d) {
                    return "translate(" + d.x + "," + d.y + ")";
                });

                text.attr("transform", function (d) {
                    return "translate(" + d.x + "," + d.y + ")";
                });
            }

            // sort the links by source, then target
            function sortLinks1() {
                data.links.sort(function (a, b) {
                    if (a.source > b.source) {
                        return 1;
                    } else if (a.source < b.source) {
                        return -1;
                    } else {
                        if (a.target > b.target) {
                            return 1;
                        }
                        if (a.target < b.target) {
                            return -1;
                        } else {
                            return 0;
                        }
                    }
                });
            }



            //any links with duplicate source and target get an incremented 'linknum'
            function setLinkIndexAndNum1() {
                for (var i = 0; i < data.links.length; i++) {
                    if (i != 0 &&
                        data.links[i].source == data.links[i - 1].source &&
                        data.links[i].target == data.links[i - 1].target) {
                        data.links[i].linkindex = data.links[i - 1].linkindex + 1;
                        console.log(data.links[i].linkindex)
                    } else {
                        data.links[i].linkindex = 1;
                        console.log(data.links[i].linkindex)
                    }
                    // save the total number of links between two nodes
                    if (mLinkNum[data.links[i].target + "," + data.links[i].source] !== undefined) {
                        mLinkNum[data.links[i].target + "," + data.links[i].source] = data.links[i].linkindex;
                    } else {
                        mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex;
                    }
                }
            }

            function setLinkIndexAndNum() {

                for (var i = 0; i < data.links.length; i++) {
                    if (i != 0 &&
                        data.links[i].source == data.links[i - 1].source &&
                        data.links[i].target == data.links[i - 1].target) {
                        data.links[i].linkindex = data.links[i - 1].linkindex + 1;
                    }
                    else {
                        data.links[i].linkindex = 1;
                    };
                };
            }
        }
    </script>
</head>
<body>
     <form id="form1" runat="server">
    <div>
    <script src="//d3js.org/d3.v3.min.js"></script>
        <%--<textarea runat="server" id="textarea" cols="80" rows="20"></textarea>
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>--%>
    </div>
        <div id="graphContainer" class="graphContainer"></div>
    </form>
</body>
</html>

is there any way of applying this kind of functionality in d3js?

There are several ways to make it. This is one of them:

circle.on("click", function(d) {
    var thisNode = d.id
    var connected = data.links.filter(function(e) {
        return e.source === thisNode || e.target === thisNode
    });
    circle.attr("opacity", function(d) {
        return (connected.map(d => d.source).indexOf(d.id) > -1 || connected.map(d => d.target).indexOf(d.id) > -1) ? 1 : 0.1
    });

    path.attr("opacity", function(d) {
        return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1
    });

Check the demo with your code:

  var color = d3.scale.category20(); //try{ // var data = JSON.parse(text); //} catch (e) { // window.alert("sometext: "+e); //} var data = { "nodes": [{ "id": 127230, "name": "Optimization of query evaluation algorithms", "citation": 26, "group": 10 }, { "id": 127254, "name": "Flow algorithms for parallel query optimization", "citation": 22, "group": 10 }, { "id": 127380, "name": "Randomized approximation algorithms for query optimization problems on two processors", "citation": 14, "group": 10 }, { "id": 127438, "name": "Optimization algorithms for simultaneous multidimensional queries in OLAP environments", "citation": 12, "group": 10 }, { "id": 127063, "name": "Query optimization in database systems", "citation": 230, "group": 10 }, { "id": 127158, "name": "Query optimization in a memory-resident domain relational calculus database system", "citation": 41, "group": 10 }, { "id": 129760, "name": "An Overview of TQuel", "citation": 22, "group": 10 }, { "id": 129867, "name": "ADVISORS", "citation": 10, "group": 10 }, { "id": 129872, "name": "Tellabs and THRIP through the Telkom Centre of Excellence at Rhodes University.", "citation": 10, "group": 10 }, { "id": 127412, "name": "Optimal service ordering in decentralized queries over web services", "citation": 13, "group": 10 }, { "id": 130856, "name": "Queries over Web Services", "citation": 10, "group": 10 }, { "id": 130959, "name": "Exploiting Parallelism to Accelerate Keyword Search On Deep-web Sources", "citation": 10, "group": 10 }, { "id": 131199, "name": "Contents lists available at ScienceDirect Future Generation Computer Systems", "citation": 10, "group": 10 }, { "id": 131211, "name": "Flow Algorithms for Parallel Query Optimization", "citation": 10, "group": 10 }, { "id": 127373, "name": "Multi-query Optimization for On-Line Analytical Processing", "citation": 14, "group": 10 }, { "id": 133379, "name": "Concise descriptions of subsets of structured sets", "citation": 21, "group": 10 }], "links": [{ "source": 127230, "target": 127063, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 127158, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 129760, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 129867, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 129872, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127230, "target": 127063, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127230, "target": 127158, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127230, "target": 129760, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127230, "target": 129867, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127230, "target": 129872, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 127412, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 130856, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 130959, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 131199, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 131211, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127254, "target": 127412, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 130856, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 130959, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 131199, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127254, "target": 131211, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127438, "target": 127373, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127438, "target": 133379, "name": "c1", "value": 10, "grouo": 1 }, { "source": 127438, "target": 127373, "name": "c1", "value": 10, "grouo": 9 }, { "source": 127438, "target": 133379, "name": "c1", "value": 10, "grouo": 9 }] }; // used to store the number of links between two nodes. // mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex; var mLinkNum = {}; // sort links first // sortLinks(); data.links.sort(function(a, b) { if (a.source > b.source) { return 1; } else if (a.source < b.source) { return -1; } else { if (a.target > b.target) { return 1; } if (a.target < b.target) { return -1; } else { return 0; } } }) // set up linkIndex and linkNumer, because it may possible multiple links share the same source and target node setLinkIndexAndNum(); var w = 1345, h = 1000; var force = d3.layout.force() .size([w, h]) .linkDistance(100) .charge(-800) .on("tick", tick); var svg = d3.select("body").append("svg:svg") .attr("width", w) .attr("height", h); var color = d3.scale.category10() var edges = []; data.links.forEach(function(e) { var sourceNode = data.nodes.filter(function(n) { return n.id === e.source; })[0], targetNode = data.nodes.filter(function(n) { return n.id === e.target; })[0]; edges.push({ source: sourceNode, target: targetNode, name: e.name, value: e.value, linkindex: e.linkindex, grouo: e.grouo }); }); force .nodes(data.nodes) .links(edges) .start(); var path = svg.append("svg:g") .selectAll("line") .data(edges) .enter().append("svg:path") .attr("class", "link") .style("stroke-width", function(d, i) { return Math.sqrt(d.value); }).style('stroke', function(d) { return color(d.grouo); }); var circle = svg.append("svg:g") .selectAll("circle") .data(force.nodes()) .enter().append("svg:circle") .attr("r", function(d) { return (Math.sqrt(d.citation)); }) .style("fill", function(d) { return color(d.group); }) .call(force.drag); var text = svg.append("svg:g") .selectAll("g") .data(force.nodes()) .enter().append("svg:g"); // A copy of the text with a thick white stroke for legibility. //text.append("svg:text") //.attr("x", 8) //.attr("y", ".31em") //.attr("class", "shadow") //.text(function (d) { //return d.name; //}); text.append("svg:text") .attr("x", 8) .attr("y", ".31em") .text(function(d) { // return d.name; }); circle.on("click", function(d) { var thisNode = d.id var connected = data.links.filter(function(e) { return e.source === thisNode || e.target === thisNode }); circle.attr("opacity", function(d) { return (connected.map(d => d.source).indexOf(d.id) > -1 || connected.map(d => d.target).indexOf(d.id) > -1) ? 1 : 0.1 }); path.attr("opacity", function(d) { return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1 }); }) // Use elliptical arc path segments to doubly-encode directionality. function tick() { path.attr("d", function(d, i) { var dx = d.target.x - d.source.x, dy = d.target.y - d.source.y, dr = 30 * d.linkindex; //linknum is defined above var output = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; //console.log(d) return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; }); // Add tooltip to the connection path path.append("svg:title") .text(function(d, i) { return d.name; }); circle.attr("transform", function(d) { return "translate(" + dx + "," + dy + ")"; }); text.attr("transform", function(d) { return "translate(" + dx + "," + dy + ")"; }); } // sort the links by source, then target function sortLinks1() { data.links.sort(function(a, b) { if (a.source > b.source) { return 1; } else if (a.source < b.source) { return -1; } else { if (a.target > b.target) { return 1; } if (a.target < b.target) { return -1; } else { return 0; } } }); } //any links with duplicate source and target get an incremented 'linknum' function setLinkIndexAndNum1() { for (var i = 0; i < data.links.length; i++) { if (i != 0 && data.links[i].source == data.links[i - 1].source && data.links[i].target == data.links[i - 1].target) { data.links[i].linkindex = data.links[i - 1].linkindex + 1; console.log(data.links[i].linkindex) } else { data.links[i].linkindex = 1; } // save the total number of links between two nodes if (mLinkNum[data.links[i].target + "," + data.links[i].source] !== undefined) { mLinkNum[data.links[i].target + "," + data.links[i].source] = data.links[i].linkindex; } else { mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex; } } } function setLinkIndexAndNum() { for (var i = 0; i < data.links.length; i++) { if (i != 0 && data.links[i].source == data.links[i - 1].source && data.links[i].target == data.links[i - 1].target) { data.links[i].linkindex = data.links[i - 1].linkindex + 1; } else { data.links[i].linkindex = 1; }; }; } 
  path.link { fill: none; stroke: #666; stroke-width: 1.5px; } circle { fill: #ccc; stroke: #333; stroke-width: 1.5px; } text { font: 10px sans-serif; pointer-events: none; } text.shadow { stroke: #fff; stroke-width: 3px; stroke-opacity: .8; } body { background-color: white; margin: 0px; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM