{
addPanel;
function dragged(d) {
d.subject.x = d.x;
d.subject.y = d.y;
update();
}
function draggedAdjust(d) {
d.subject.width += d.dx;
d.subject.height += d.dy;
d.subject.width = d.subject.width < 50 ? 50 : d.subject.width;
d.subject.height = d.subject.height < 50 ? 50 : d.subject.height;
update();
}
function update() {
svg
.selectAll(".rect-main")
.attr("x", (d) => d.x)
.attr("y", (d) => d.y)
.attr("width", (d) => d.width)
.attr("height", (d) => d.height);
svg
.selectAll(".rect-adjuster")
.attr("x", (d) => d.x + d.width - 20)
.attr("y", (d) => d.y + d.height - 20);
svg
.selectAll("text")
.attr("x", (d) => d.x + 20)
.attr("y", (d) => d.y + 20);
svg.selectAll("path").attr("d", link);
const div = document.getElementById("summary-zone");
div.innerHTML = "";
d3.select(div)
.selectAll("div")
.data(data)
.enter()
.append("div")
.text((d) => Object.entries(d).join(";\t").replaceAll(",", ":"));
}
// DOM.svg is just an Observable utility for creating an SVG node
const svg = d3
.select(DOM.svg(width, height))
.attr("style", "background: #aaaaaa");
// Create some data for the nodes
// Define connections between nodes
const links = [
// {
// source: data[0],
// target: data[1]
// },
// {
// source: data[0],
// target: data[2]
// }
];
{
const n = data.length;
for (let i = 0; i < n; ++i) {
for (let j = i; j < n; ++j) {
links.push({ source: data[i], target: data[j] });
}
}
}
// Set up the utility for generating path strings
const link = d3
.linkHorizontal()
.source(function (d) {
// Calculate the (x, y) position for the link attachment
// on the source node.
return [
d.source.x + d.source.width / 2,
d.source.y + d.source.height / 2
];
})
.target(function (d) {
return [
d.target.x + d.target.width / 2,
d.target.y + d.target.height / 2
];
});
// Set up D3's drag behavior
const drag = d3.drag().on("drag", dragged);
const dragAdjust = d3.drag().on("drag", draggedAdjust);
// Initialize the nodes
// Initilize the links between nodes
svg
.selectAll("path")
.data(links)
.enter()
.append("path")
.attr("d", link)
.style("fill", "none")
.style("stroke", "#56445D30")
.style("stroke-width", "4px");
const groups = svg.append("g").selectAll("g").data(data).enter().append("g"); // Apply the drag behaviour to all rects
groups
.append("rect")
.attr("class", "rect-main")
.attr("x", (d) => d.x)
.attr("y", (d) => d.y)
.attr("width", (d) => d.width)
.attr("height", (d) => d.height)
.style("fill", "#ffffffa0")
.style("stroke", "#56445D")
.style("stroke-width", "2px")
.call(drag);
groups
.append("rect")
.attr("class", "rect-adjuster")
.attr("x", (d) => d.x + d.width - 20)
.attr("y", (d) => d.y + d.height - 20)
.attr("width", (d) => 20)
.attr("height", (d) => 20)
.style("fill", "white")
.style("stroke", "#56445D")
.style("stroke-width", "2px")
.style("fill", (d, i) => d3.schemeTableau10[i % 10] + "50")
.call(dragAdjust);
groups
.append("text")
.text((d) => d.name)
.attr("x", (d) => d.x + 20)
.attr("y", (d) => d.y + 20)
.attr("fill", (d, i) => d3.schemeTableau10[i % 10])
.attr("style", "pointer-events: none; font-size: 20");
// This is just to tell the notebook to show the SVG.
update();
return svg.node();
}