简体   繁体   中英

D3 drag + links not moving

I have a series of nodes and links in a force directed graph and I have the nodes able to drag and return to their starting position nicely but the links won't follow them. I thought the tick function would automatically update the ends of each link... I have a fiddle here

My two main questions thus far are a.) why don't the links follow the nodes and how do I make it do so... b.) I've noticed when I run the script either on fiddle or on my browser there is a strange delay until I can drag a node, why is that and how do I fix it?

<!DOCTYPE html>
<meta charset="utf-8">
<style>

    .Chip{
        fill: red;
        /*stroke: black;*/
        stroke-width: 2px;
    }
    .Abstraction{
        fill: blue;
        /*stroke: black;*/
        stroke-width: 2px;
    }
    .Properties{
        fill: green;
        stroke: black;
        stroke-width: 2px;
    }
    .link{
    stroke: #777;
    stroke-width: 2px;
    }


</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
        var width = 960, height = 500, colors = d3.scale.category10();
        var svg = null, force = null;
        var circle = null, path = null;
        var nodes = null, links = null;
        var nodesArray = null, linkArray = null;
        var count = 0;
        var element = "body"; var numEdges = 4, numNodes = 5;
        var i = 0; var L = 16, r = 12, lineLimit = 10;
        var d = 2 * r + L;
        var R = (count - 1) * d;
        var m = width / 2;
        var X;
        var drag = d3.behavior.drag()
                    .on('dragstart', dragstart)
                    .on('drag', drag)
                    .on('dragend', dragend);
        svg = d3.selectAll(element).append('svg').attr('width', width).attr('height', height);
        nodes = d3.range(numNodes).map(function () {
            X = m - (R / 2) + (i * d);
            ++i;
            return {
                x: X,
                y: (height) / 3,
                fx: X,
                fy: height / 3,
                id: i-1,
                reflexive: true
            };           
        });
        for (var i = 0; i < numNodes; ++i) {
            d3.select(element).append("h3").text("Node " + i + ": " + nodes[i].id);
        }

        i = -1;
        links = d3.range(numEdges).map(function () {
            i++;
            return {
                //
                source: nodes[i],
                target: nodes[i+1],
                left: false,
                right: true
            }
        });
        for (var i = 0; i < numEdges; ++i) {
            d3.select(element).append("h3").text("Source: " + links[i].source.id + " Target: " + links[i].target.id);
        }

        force = d3.layout.force().size([width, height]).nodes(nodes).links(links).linkDistance(40).linkStrength(0.1).charge(-300);

        linkArray = svg.selectAll('.link').data(links).enter().append('line').attr('class', 'link')
            .attr('x1', function (d) {
                return nodes[d.source.id].x;
            })
            .attr('y1', function (d) { return nodes[d.source.id].y; })
            .attr('x2', function (d) { return nodes[d.target.id].x; })
            .attr('y2', function (d) { return nodes[d.target.id].y; });

        nodeArray = svg.selectAll("circle").data(nodes).enter().append('circle').attr('class', "Properties").attr('r', 12)
            .attr('cx', function (d) { return d.x })
            .attr('cy', function (d) { return d.y })
            .style('cursor', 'pointer').call(drag);

        force.on('tick', tick);
        force.start();
        function dragmove(d) {
            d3.select(this)
                .attr("cx", d.x = Math.max(radius, Math.min(width - radius, d3.event.x)))
                .attr("cy", d.y = Math.max(radius, Math.min(height - radius, d3.event.y)));
        }
        var originalPosition = [];
        function dragstart(d) {
            originalPosition[0] = d.x;
            originalPosition[1] = d.y;
            console.log("Start: ", originalPosition[0], originalPosition[1]);
        }
        function drag() {
            var m = d3.mouse(this);
            d3.select(this)
                    .attr('cx', m[0])
                    .attr('cy', m[1]);
        }

        function dragend(d) {
            console.log("End: ", d.x, d.y);
            d3.select(this).transition().attr('cx', originalPosition[0]).attr('cy', originalPosition[1]);
        }
        function tick() {

            nodeArray
                .attr('cx', function (d) { return d.x; })
                .attr('cy', function (d) { return d.y; });
            console.log("ticking");

            linkArray
                .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; });

        }

</script>

I know this is super late, but maybe it will help someone else.

Basically, you were setting the node positions on dragstart but not the links. So as you set the node position just call the tick function to move the links.

Here is your updated drag function :

function dragstart(d, i) {
        force.stop() // stops the force auto positioning before you start dragging

        originalPosition[0] = d.x;
        originalPosition[1] = d.y;
    }

    function dragmove(d, i) {
        d.px += d3.event.dx;
        d.py += d3.event.dy;
        d.x += d3.event.dx;
        d.y += d3.event.dy; 
        tick();
    }

    function dragend(d, i) {
        d.x = originalPosition[0];
        d.y = originalPosition[1];

        d3.select(this).transition().attr('cx', originalPosition[0]).attr('cy', originalPosition[1]);
        tick();
    }

Notice the names on these functions too. You had a variable 'drag' but you also had a function 'drag' so I don't know how it actually worked without throwing an error.

Updated fiddle : https://jsfiddle.net/g9g9xe6k/6/

A tad late, but hope it helps :)

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