react-force-graph
react-force-graph copied to clipboard
Prevent dragging node off canvas
I imagine this functionality exists, I am just having trouble figuring out where/how. I would simply like to prevent the user from dragging a node off the canvas, like in this example:
the following code is basically working for me, although (1) I don't know how to get the node radius in pixels (or graph units) and (2) when I drag a node up against the edge, it causes all the nodes to stutter (quickly shake a little)
function handleEngineTick() {
// @ts-ignore
const container = forceRef.current;
graphDataMemoized.nodes.forEach((node: any) => {
const coordinates = container.graph2ScreenCoords(node.x, node.y);
const boxWidth = displayWidth;
const boxHeight = displayHeight;
const nodeRadius = NODE_R * node.val;
const margin = 15; // how to get node radius? If we can get it we don't need margin
// right boundary
if (coordinates.x > (boxWidth - nodeRadius - margin)) {
const desiredScreenX = boxWidth - nodeRadius - margin;
const graphUnits = container.screen2GraphCoords(desiredScreenX, node.y);
node.x = graphUnits.x;
}
// left boundary
if (coordinates.x < 0 + nodeRadius + margin) {
const desiredScreenX = nodeRadius + margin;
const graphUnits = container.screen2GraphCoords(desiredScreenX, node.y);
node.x = graphUnits.x;
}
// bottom boundary
if (coordinates.y > (boxHeight - nodeRadius - margin)) {
const desiredScreenY = boxHeight - nodeRadius - margin;
const graphUnits = container.screen2GraphCoords(node.x, desiredScreenY);
node.y = graphUnits.y;
}
// top boundary
if (coordinates.y < 0 + nodeRadius + margin) {
const desiredScreenY = nodeRadius + margin;
const graphUnits = container.screen2GraphCoords(node.x, desiredScreenY);
node.y = graphUnits.y;
}
});
}
Hey there! Thanks for your solution. I've used it in my project.
Concerning the way to get the radius, I found it inspecting the source code of force-graph module. See this link: https://github.com/vasturiano/force-graph/blob/06e372da6a02b838395e7b85c26fd05d5e63d31c/src/force-graph.js#LL294C7-L294C90
export function getNodeRadius(node) {
return Math.sqrt(Math.max(0, node.val || 1)) * NODE_REL_SIZE
}
Hope it helps! And thank you a lot :)