d3用一条线连接不同组的矩形

时间:2015-08-03 23:36:57

标签: javascript d3.js svg

我正在尝试连接来自不同组的两个矩形,但这些组可以拖动。如果组是静态的,我可以完成工作。但是当我拖动大组时,线条行为变得混乱。我想点击一个圆圈并开始绘制线条,当鼠标移动时移动线条,然后我想点击另一个圆圈并结束线条。这是我工作的fiddle,有人可以帮我一把吗?

<g id="a" transform="translate(0,0)">
    <g>
        <rect x="10" y="10" width="200" height="200" fill="red"></rect>
        <circle r="5" cx="10" cy="105" fill="blue"></circle>
        <circle r="5" cx="210" cy="105" fill="blue"></circle>
        <line id="lineOne" x1="210" y1="105" x2="200" y2="200" style="stroke: green; stroke-width: 3px"></line>

    </g>
    <g id="b" class="e">
        <rect x="20" y="20" width="50" height="50" fill="black"></rect>
        <circle r="5" cx="20" cy="45" fill="blue"></circle>
        <circle r="5" cx="70" cy="45" fill="blue"></circle>
    </g>
    <g id="c" class="e">
        <rect x="90" y="20" width="50" height="50" fill="black"></rect>
        <circle r="5" cx="90" cy="45" fill="blue"></circle>
        <circle r="5" cx="140" cy="45" fill="blue"></circle>
    </g>
</g>

<script>

    d3.select('svg').on('mousemove', function () {
        d3.select('#lineOne').attr('x2', d3.mouse(this)[0]).attr('y2', d3.mouse(this)[1]);

    })
    ;
    d3.select('#a').call(d3.behavior.drag()
            .origin(function () {
                var t = d3.select(this);
                return {
                    x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
                    y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
                };
            })
            .on('drag', function () {
                d3.select(this).attr('transform', 'translate(' + d3.event.x + ',' + d3.event.y + ')');

            }));

    d3.selectAll('.e')
            .call(d3.behavior.drag()
                    .origin(function () {
                        var t = d3.select(this);
                        return {
                            x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
                            y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
                        };
                    }
            )
                    .on('dragstart', function () {
                        d3.event.sourceEvent.stopPropagation();
                    })
                    .on('drag', function () {
                        var parent = d3.select('#a').select('rect');
                        var current = d3.select(this).select('rect');
                        var dx = d3.event.x;
                        var dy = d3.event.y;
                        var x, y;


                        if (((Number(current.attr('x')) + dx) > Number(parent.attr('width')))) {
                            console.log('x case');
                            x = Number(parent.attr('width')) - Number(current.attr('width')) - Number(current.attr('x'));
                        }
                        else if (dx < 0 && (Number(current.attr('x')) - Number(parent.attr('x')) + dx  ) < 0) {
                            x = -1 * Number(current.attr('x')) + 20;
                        }
                        else {
                            x = dx;
                        }


                        if (((Number(current.attr('y')) + dy) > Number(parent.attr('height')))) {
                            y = Number(parent.attr('height')) - Number(current.attr('height')) - Number(current.attr('y'));

                        }
                        else if (dy < 0 && (Number(current.attr('y')) - Number(parent.attr('y')) + dy  ) < 0) {
                            y = -1 * Number(current.attr('y')) + 20;
                        }
                        else {
                            y = dy;
                        }

                        d3.select(this).attr('transform', 'translate(' + x + ',' + y + ')');
                    }))
            .on('dragend', function () {
                d3.select(this).call(d3.behavior.drag().origin(function () {

                    var t = d3.select(this);
                    return {x: t.attr("x"), y: t.attr("y")};
                }))
            })

    ;


</script>

1 个答案:

答案 0 :(得分:4)

拖动矩形时,您还必须更新链接。使用变换矩阵计算x1,x2,y1和y2位置。我创建了一个有效的代码片段。有关详细信息,请参阅代码。如果有的话,请随时提出疑问。

d3.selectAll(".line")[0]
.forEach(function(el) {
    var d = d3.select(el).data()[0],
        line = d3.select(el);
    if (d.src == g.attr("id")) {
        var pt = svg.createSVGPoint();
        pt.x = parseInt(g.select("circle." + d.sPos).attr("cx"));
        pt.y = parseInt(g.select("circle." + d.sPos).attr("cy"));
        pt = pt.matrixTransform(g.node().getCTM());
        pt = pt.matrixTransform(d3.select("#a").node().getCTM().inverse());
        line.attr('x1', pt.x).attr('y1', pt.y);
    } else if (d.tgt == g.attr("id")) {
        var pt = svg.createSVGPoint();
        pt.x = parseInt(g.select("circle." + d.ePos).attr("cx"));
        pt.y = parseInt(g.select("circle." + d.ePos).attr("cy"));
        pt = pt.matrixTransform(g.node().getCTM());
        pt = pt.matrixTransform(d3.select("#a").node().getCTM().inverse());
        line.attr('x2', pt.x)
            .attr('y2', pt.y);
    }
});

&#13;
&#13;
var svg = d3.select('svg').node();
d3.select('svg').on('mousemove', function() {
    if (dragging) {
        var rad = 5;
        var x = d3.mouse(d3.select('#a').node())[0],
            y = d3.mouse(d3.select('#a').node())[1];
        d3.select('#dummyPath').attr('x2', x - rad).attr('y2', y - rad);
        d3.select('#dummyPath').style("display", "block")
    }
});

d3.select('#a').call(d3.behavior.drag()
    .origin(function() {
        var t = d3.select(this);
        return {
            x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
            y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
        };
    })
    .on('drag', function() {
        d3.select(this).attr('transform', 'translate(' + d3.event.x + ',' + d3.event.y + ')');

    }));

d3.selectAll('.e')
    .call(d3.behavior.drag()
        .origin(function() {
            var t = d3.select(this);
            return {
                x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
                y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
            };
        })
        .on('dragstart', function() {
            d3.event.sourceEvent.stopPropagation();
        })
        .on('drag', function() {
            var g = d3.select(this);
            var parent = d3.select('#a').select('rect');
            var current = d3.select(this).select('rect');
            var dx = d3.event.x;
            var dy = d3.event.y;

            var x, y;


            if (((Number(current.attr('x')) + dx) > Number(parent.attr('width')))) {
                console.log('x case');
                x = Number(parent.attr('width')) - Number(current.attr('width')) - Number(current.attr('x'));
            } else if (dx < 0 && (Number(current.attr('x')) - Number(parent.attr('x')) + dx) < 0) {
                x = -1 * Number(current.attr('x')) + 20;
            } else {
                x = dx;
            }


            if (((Number(current.attr('y')) + dy) > Number(parent.attr('height')))) {
                y = Number(parent.attr('height')) - Number(current.attr('height')) - Number(current.attr('y'));

            } else if (dy < 0 && (Number(current.attr('y')) - Number(parent.attr('y')) + dy) < 0) {
                y = -1 * Number(current.attr('y')) + 20;
            } else {
                y = dy;
            }
            
            d3.select(this).attr('transform', 'translate(' + x + ',' + y + ')');           
       d3.selectAll(".line")[0]
                .forEach(function(el) {
                    var d = d3.select(el).data()[0],
                        line = d3.select(el);                                       
                    if (d.src == g.attr("id")) {
                        var pt = svg.createSVGPoint();
                    pt.x = parseInt(g.select("circle." + d.sPos).attr("cx"));
                    pt.y = parseInt(g.select("circle." + d.sPos).attr("cy"));
                         pt = pt.matrixTransform(g.node().getCTM());
                    pt = pt.matrixTransform(d3.select("#a").node().getCTM().inverse());
                        line.attr('x1', pt.x).attr('y1', pt.y);
                    } else if (d.tgt == g.attr("id")) {
                                      var pt = svg.createSVGPoint();
                    pt.x = parseInt(g.select("circle." + d.ePos).attr("cx"));
                    pt.y = parseInt(g.select("circle." + d.ePos).attr("cy"));
                         pt = pt.matrixTransform(g.node().getCTM());
                    pt = pt.matrixTransform(d3.select("#a").node().getCTM().inverse());
                        line.attr('x2', pt.x)
                            .attr('y2', pt.y);
                    }
                });
  }))
    .on('dragend', function() {
        d3.select(this).call(d3.behavior.drag().origin(function() {

            var t = d3.select(this);
            return {
                x: t.attr("x"),
                y: t.attr("y")
            };
        }))
    })

;
var dragging = false;
var drag = d3.behavior.drag()
    .on("dragstart", function() {
        dragging = true;
        d3.event.sourceEvent.stopPropagation();
        var x = d3.mouse(d3.select('#a').node())[0],
            y = d3.mouse(d3.select('#a').node())[1];
        d3.select('#dummyPath').attr('x1', x).attr('y1', y);        
    })
    .on("dragend", function() {
        var sCircle = d3.select(this);
        var eCircle = d3.select(d3.event.sourceEvent.target);
        dragging = false;
        if (d3.event.sourceEvent.target.tagName == "circle" && this != d3.event.sourceEvent.target) {
            var rad = 5;
            var source = d3.select(this.parentNode).attr("id");
            var target = d3.select(d3.event.sourceEvent.target.parentNode).attr("id");
            var x1 = d3.select('#dummyPath').attr('x1'),
                y1 = d3.select('#dummyPath').attr('y1'),
                x2 = d3.mouse(d3.select('#a').node())[0],
                y2 = d3.mouse(d3.select('#a').node())[1];
            d3.select("#a")
                .append("line")
                .datum({
                    src: source,
                    tgt: target,
                    sPos: sCircle.attr("class"),
                    ePos: eCircle.attr("class")
                })
                .attr("class", "line")
                .attr("x1", x1)
                .attr("y1", y1)
                .attr("x2", x2)
                .attr('y2', y2);
        }
        d3.select('#dummyPath').style("display", "none");

    });

d3.selectAll("circle").call(drag);
&#13;
#dummyPath {  
  stroke: green; 
  stroke-width: 3px;
  display:none;
  stroke-dasharray: 5 7;
}

.line {
  stroke: blue;
  stroke-width: 3px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="500" height="500">

    <g id="a" transform="translate(0,0)">
        <g id="d">
            <rect x="10" y="10" width="200" height="200" fill="red"></rect>
            <circle r="5" class="left" cx="10" cy="105" fill="blue"></circle>
            <circle r="5" class="right" cx="210" cy="105" fill="blue"></circle>

        </g>
        <g id="b" class="e">
            <rect x="20" y="20" width="50" height="50" fill="black"></rect>
            <circle class="left" r="5" cx="20" cy="45" fill="blue"></circle>
            <circle class="right" r="5" cx="70" cy="45" fill="blue"></circle>
        </g>
        <g id="c" class="e">
            <rect x="90" y="20" width="50" height="50" fill="black"></rect>
            <circle r="5" class="left" cx="90" cy="45" fill="blue"></circle>
            <circle r="5" class="right" cx="140" cy="45" fill="blue"></circle>
        </g>       
      <line id="dummyPath" x1="0" y1="0" x2="0" y2="0" class="dummy"></line>
    </g>   

</svg>
&#13;
&#13;
&#13;

<强>更新

JSFiddle