D3拖动+链接不动

时间:2015-09-25 02:52:13

标签: javascript d3.js

我在力导向图中有一系列节点和链接,我有节点可以很好地拖动并返回到它们的起始位置,但链接不会跟随它们。我认为滴答功能会自动更新每个链接的末尾......我有一个小提琴here

到目前为止我的两个主要问题是:。)为什么链接不遵循节点,我怎么做呢... b。)我注意到当我在小提琴或者小提琴上运行脚本时我的浏览器有一个奇怪的延迟,直到我可以拖动一个节点,为什么这样,我该如何修复它?

<!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>

1 个答案:

答案 0 :(得分:0)

我知道这已经太晚了,但也许它会帮助别人。

基本上,您是在dragstart上设置节点位置而不是链接。因此,当您设置节点位置时,只需调用tick函数来移动链接。

这是您更新的拖动功能:

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();
    }

注意这些功能的名称。你有一个变量&#39;拖动&#39;但你也有一个功能&#39;拖动&#39;所以我不知道如何在不抛出错误的情况下实际工作。

更新了小提琴:https://jsfiddle.net/g9g9xe6k/6/

有点迟了,但希望有所帮助:)。