简体   繁体   中英

Moving connected rectangles in d3js

I am trying to connect two draggable rectangles in d3js. My requirement is to

  1. Have different rectangles ( eg. A, B, C)
  2. All the rectangles should be draggable
  3. When I click on a rectangle it should start to draw a line (eg. If I click on A first, the line should start from Ax, Ay The line end should move with mouse point)
  4. WhenI clik on a second rectangle, the line should end in that element (eg. If I click on B after A, A & B should be connected now)

So far I have can drag the rectangles, I can connect them if they are static. But When I move the rectangles after joing them then the line should move with the rectangle.

Here is the fiddle of my work. Can anyone guide me here?

<svg id="main" width="500" height="500" style="background-color: white">
    <rect id="a" x="100" y="100" height="50" width="50" style="fill: blue"></rect>
    <rect id="b" x="400" y="400" height="50" width="50" style="fill: blue"></rect>
    <line id="c" x1="100" y1="100"  y2="400" x2="400" style="stroke:rgb(255,0,0);stroke-width:2;display:none"></line>
</svg>

    function move() {
        d3.select(this)
                .attr('x', d3.event.x -   parseInt(d3.select(this).attr("width")) / 2)
                .attr('y', d3.event.y - parseInt(d3.select(this).attr("height")) / 2);


    }

 var drag = d3.behavior.drag().on('drag', move);

d3.select("#a").on('mousedown', function(d){
     d3.select("#c").style("display","");//make the line visible when mouse click is down.
}) .call(drag);
d3.select("#b").on('mouseup', function(d){
     d3.select('#c')
        .attr('x2', 400)
        .attr('y2', 400);
//remove all the listeners as we have made the connection line    
    d3.select("#main").on('mousemove',null);
    d3.select("#a").on('mousedown',null);
    d3.select("#b").on('mouseup',null);
}) .call(drag);
d3.select("#main").on('mousemove', function(d){
    //on mouse move update the line.
    var mouseLoc = d3.mouse(this);
    d3.select('#c')
        .attr('x2', mouseLoc[0]-5)
        .attr('y2', mouseLoc[1]-5);

});

You will need to update the line with attributes accordingly.

Here is an example: http://jsfiddle.net/cyril123/kbj4xsmm/12/

var myMapLookup = {c:{ source:'a', target:'b'}};//this will map the line id to its source and target rectangles. this help you track which line is linked to which 2 rectangles.
function move(lineID, me) {
    //lineID will gve the id of the line.
    var nx = d3.event.x-parseInt(d3.select(me).attr("width"))/2
    var ny = d3.event.y-parseInt(d3.select(me).attr("height"))/2
    d3.select(me).attr('x', nx)
                   .attr('y', ny);
    //change the line's x and y on dragging
    //if source update the x1 and y1
    if(d3.select(me).attr('id') == myMapLookup.c.source){
        d3.select('#' + lineID).attr('x1', nx).attr('y1', ny);
    }
    //if source update the x2 and y2
    if(d3.select(me).attr('id') == myMapLookup.c.target){
        d3.select('#' + lineID).attr('x2', nx).attr('y2', ny);
    }

}

d3.select("#a").on('mousedown', function(d){
     d3.select("#c").style("display","");//make the line visible when mouse click is down.
    d3.select("#c").data({src: 'a', target: 'b'})
});
d3.select("#b").on('mouseup', function(d){
     d3.select('#c')
        .attr('x2', 400)
        .attr('y2', 400);
//remove all the listeners as we have made the connection line    
    d3.select("#main").on('mousemove',null);
    d3.select("#a").on('mousedown',null);
    d3.select("#b").on('mouseup',null);
//attach drag listener to all rectangles

    var dragA = d3.behavior.drag().on("drag", function(){move('c', this)});
    d3.select("#a").call(dragA);
    var dragB = d3.behavior.drag().on("drag", function(){move('c', this)});
    d3.select("#b").call(dragB);
});
d3.select("#main").on('mousemove', function(d){
    //on mouse move update the line.
    var mouseLoc = d3.mouse(this);
    d3.select('#c')
        .attr('x2', mouseLoc[0]-5)
        .attr('y2', mouseLoc[1]-5);

});

You can make use of the myMapLookup to rgister line with source and target rectangles. This way you can have n rectangles and n lines and same drag code can work across.

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