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.