简体   繁体   中英

Add text on hover, image on the svg circle and make the nodes less sticky in a d3 graph

I have been trying to create a static d3 graph. Following is my html code with the script:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="style.css">
    </head>

    <body>
        <script src="//d3js.org/d3.v3.min.js"></script>
        <script>

            var width = 960,
                height = 500;

            var force = d3.layout.force()
                .size([width, height])
                .charge(-50)
                .gravity(0)
                .linkDistance(50)
                .on("tick", tick)
                .start();


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

            // build the arrow.
            svg.append("svg:defs").selectAll("marker")
                .data(["end"])      // Different link/path types can be defined here
                .enter().append("svg:marker")    // This section adds in the arrows
                .attr("id", String)
                .attr("viewBox", "0 -5 10 10")
                .attr("refX", 20)
                .attr("refY", 0)
                .attr("markerWidth", 12)
                .attr("markerHeight", 12)
                .attr("orient", "auto")
                .append("svg:path")
                .attr("d", "M0,-5L10,0L0,5");

            var link = svg.selectAll(".link");
            var node = svg.selectAll(".node");


            d3.json("position.json", function(error, graph) {
                if (error) throw error;

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

                link = link.data(graph.links)
                    .enter().append("line")
                    .attr("class", "link")
                    .attr("marker-end", "url(#end)"); // add the arrow with and identify it wiht the tag "end" :)

                node = node.data(graph.nodes)
                    .enter().append("circle")
                    .attr("class", "node")
                    .attr("r", 15)
                    .call(force.drag);

                // Append custom images from json ----- DOESNT WORK
                node.append("svg:image")
                    .attr("xlink:href",  function(d) { return d.img;}) // update the node with the image
                    .attr("x", function(d) { return -25;}) // how far is the image from the link??
                    .attr("y", function(d) { return -25;}) // --- same ---
                    .attr("height", 35) // size
                    .attr("width", 35);

                // Get information on hover ----- DOESNT WORK
                node.append("text")
                    .attr("class", "nodetext")
                    .attr("x",function(d) { return -25;})
                    .attr("y",function(d) { return -25;})
                    .text(function(d) { return d.text; });

                // add title to the image :) ----- DOESNT WORK
                node.append("title")
                    .attr("dx", 12) // how far is the text from the link??
                    .attr("dy", ".35em") // --- same ---
                    .text(function(d) { return d.name });

            });

            function tick() {
                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 + ")"; });

                force.stop();
            }

            function dragstart(d) {
                d3.select(this).classed("fixed", d.fixed = true);
            }

        </script>
    </body>
</html>

Following is my json file:

{
  "nodes": [
    {"x": 200, "y": 200, "title": "lmao", "t": "Info here", "img": "https://cdn2.iconfinder.com/data/icons/capsocial-square-flat-3/500/github-512.png"},
    {"x": 300, "y": 200, "title": "lmao", "t": "Info here", "img": "https://cdn2.iconfinder.com/data/icons/capsocial-square-flat-3/500/github-512.png"},
    {"x": 400, "y": 200, "title": "lmao", "t": "Info here", "img": "https://cdn2.iconfinder.com/data/icons/capsocial-square-flat-3/500/github-512.png"},
    {"x": 500, "y": 300, "title": "lmao", "t": "Info here", "img": "https://cdn2.iconfinder.com/data/icons/capsocial-square-flat-3/500/github-512.png"}
  ],
  "links": [
    {"source":  0, "target":  1},
    {"source":  1, "target":  2},
    {"source":  2, "target":  3}
  ]
}

Following is the css script:

.link {
    stroke: #ccc;
    stroke-width: 1.5px;
}

.node {
    cursor: move;
    fill: #ccc;
    stroke: #000;
    stroke-width: 1.5px;
}

.node:not(:hover) .nodetext {
    display: none;
}

The javascript embedded into the html does include code snippet for information on hover and text underneath the nodes and for an image instead of the svg circle. But I seem to have gone wrong somewhere. I also want to make the nodes less sticky and links more elastic so that they can be dragged anywhere, but I have no clue how to do that. Can anyone please help me?

Thank you

Realized how to put info on hover (multiple info):

// Append custom images
        node.append("svg:image")
            .attr("xlink:href",  function(d) { return d.img;}) // update the node with the image
            .attr("x", function(d) { return -5;}) // how far is the image from the link??
            .attr("y", function(d) { return -19;}) // --- same ---
            .attr("height", 35) // size
            .attr("width", 35)
            .on("mouseover", function(d) {
                div.transition()
                    .duration(200)
                    .style("opacity", .9);
                div .html( d.title  + "<br/>" + d.t)
                    .style("left", (d3.event.pageX + 10) + "px")
                    .style("top", (d3.event.pageY - 38) + "px");
            })
            .on("mouseout", function(d) {
                div.transition()
                    .duration(500)
                    .style("opacity", 0);
            });

with the following portion added into the css:

div.tooltip {
    position: absolute;
    text-align: center;
    width: 60px;
    height: 28px;
    padding: 2px;
    font: 12px sans-serif;
    background: lightsteelblue;
    border: 0px;
    border-radius: 8px;
    pointer-events: none;
}

and this block is then unnecessary:

// Get information on hover ----- DOESNT WORK
                node.append("text")
                    .attr("class", "nodetext")
                    .attr("x",function(d) { return -25;})
                    .attr("y",function(d) { return -25;})
                    .text(function(d) { return d.text; });

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