How to bind the node of draggable graph to a draggable rectangle

Viewed 91

Dragging of rectangles and graph work as intended in the given example. But I would like to bind the graph nodes to the rectangles underneath, so that moving a rectangle also moves the bound graph node and with it the graph link.

var width = 960,
height = 500;

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

var graph = { "nodes": [{ "x": 170, "y": 120 }, { "x": 400, "y": 100 }], "links": [{ "source": 0, "target": 1 }] }

graph.links.forEach(function (d) {
d.source = graph.nodes[d.source];
d.target = graph.nodes[d.target];
});

var dataRects = [
{ "x": 20, "y": 50, "width": 200, "height": 100 },
{ "x": 350, "y": 75, "width": 150, "height": 50 }
]

var rects = svg.append("g")
.attr("id", function () { return "g_0" })
.attr("class", "rect")
.selectAll("rect")
.data(dataRects)
.enter()
.append("rect")
.attr("id", function (d, i) { return "box_" + i })
.attr("x", function (d) { return d.x; })
.attr("y", function (d) { return d.y; })
.attr("width", function (d) { return d.width })
.attr("height", function (d) { return d.height })



.call(d3.drag()
//.on("start", function(d) {}
.on("drag", function (d) {
  const matrix = d3.select(this).node().transform.baseVal.consolidate().matrix;
  const x = matrix.e + d3.event.dx;
  const y = matrix.f + d3.event.dy;
  d3.select(this).attr("transform", `translate(${x},${y})`);
})
.on("end", function (d) {
  idOnEnd = d3.select(this).attr("id");

})
)
.attr("transform", "translate(0,0)");


var link = svg.append("g")
.attr("class", "link")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.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; });

var node = svg.append("g")
.attr("class", "node")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("id", function (d, i) { return "node_" + i; })
.attr("r", 9)
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.call(d3.drag().on("drag", dragged));

function dragged(d) {
d.x = d3.event.x, d.y = d3.event.y;
d3.select(this).attr("cx", d.x).attr("cy", d.y);
link.filter(function (l) { return l.source === d; }).attr("x1", d.x).attr("y1", d.y);
link.filter(function (l) { return l.target === d; }).attr("x2", d.x).attr("y2", d.y);
}

// var nodeSelect = d3.select("#node_0")
// d3.select("#box_0").append(function(){return nodeSelect.node()});
// d3.select("#g_0").append(() => nodeSelect.node());

  
.svg {
border: 1px solid red;
}


.node {
stroke: #555;
fill: #F00;
stroke-width: 3px;
}

.link {
stroke: #555;

stroke-width: 3px;
}

.rect {
fill: lightgray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

Tried various things that didn't work, among them making a rectangle or its group the node parent:

    var nodeSelect = d3.select("#node_0")
    d3.select("#box_0").append(function(){return nodeSelect.node()});
    d3.select("#g_0").append(() => nodeSelect.node());

The group change is reflected in the DOM but doesn't produce the desired effect. Wasn't lucky searching for pertinent posts.

The larger goal to create a flow chart, where links between rectangles are created by mouse clicks, and links are preserved and move along when rectangles are dragged around.

0 Answers
Related