I want to disable overlapping of nodes so that when a user drops a node on a location and there is already a node present, it places it next to it (either up, down or one of the sides depending on the position of the overlap)
This isn’t exactly what you are asking for, but it’s related. If instead of fixing up the location after the drop you disallowed dragging except to unoccupied locations, would that be OK? That way users get to control exactly where the node gets located while still preventing overlaps.
If so, here are two functions that you can define:
// R is a Rect in document coordinates
// NODE is the Node being moved -- ignore when looking for Parts intersecting the Rect
function isUnoccupied(r, node) {
var diagram = node.diagram;
// nested function used by Layer.findObjectsIn, below
// only consider Parts, and ignore the given Node
function navig(obj) {
var part = obj.part;
if (part === node) return null;
return part;
}
// only consider non-temporary Layers
var lit = diagram.layers;
while (lit.next()) {
var lay = lit.value;
if (lay.isTemporary) continue;
if (lay.findObjectsIn(r, navig, null, true).count > 0) return false;
}
return true;
}
// a Part.dragComputation function that prevents a Part from being dragged to overlap another Part
function avoidNodeOverlap(node, pt, gridpt) {
var bnds = node.actualBounds;
var loc = node.location;
// see if the area at the proposed location is unoccupied
var x = pt.x - (loc.x - bnds.x);
var y = pt.y - (loc.y - bnds.y);
var r = new Rect(x, y, bnds.width, bnds.height);
if (isUnoccupied(r, node)) return pt; // OK
return loc; // give up -- don't allow the node to be moved to the new location
}
Use the latter function to customize the Part.dragComputation for your node:
Yes awesome, this is even better. (the reason i wanted to drop the object next to another is because a user can add objects from popups, so i’ll still need that functionality but i can use this code to make such functionality)
only problem is that it also prevent dragging over links, so a node which has a link attached to it on the left side can not be dragged to the left. But i fixed that, and also the line ‘r = new Rect’ should be ‘r = new go.Rect’ (in my code it didn’t work). I’ll post the working code below so other people searching the forum can use the code.
Thanks a lot for your help!
–code–
var isUnoccupied = function (r, node) {
var diagram = node.diagram;
// nested function used by Layer.findObjectsIn, below
// only consider Parts, and ignore the given Node
var navig = function (obj) {
var part = obj.part;
// i used part.data.from to check if a part is a link, only links have a from property
if (part === node || part.data.from) return null;
return part;
}
// only consider non-temporary Layers
var lit = diagram.layers;
while (lit.next()) {
var lay = lit.value;
if (lay.isTemporary) continue;
if (lay.findObjectsIn(r, navig, null, true).count > 0) return false;
}
return true;
}
// a Part.dragComputation function that prevents a Part from being dragged to overlap another Part
var avoidNodeOverlap = function (node, pt, gridpt) {
var bnds = node.actualBounds;
var loc = node.location;
// see if the area at the proposed location is unoccupied
var x = pt.x - (loc.x - bnds.x);
var y = pt.y - (loc.y - bnds.y);
//in my case new Rect didnt work
var r = new go.Rect(x, y, bnds.width, bnds.height);
if (isUnoccupied(r, node)) return pt; // OK
return loc; // give up -- don't allow the node to be moved to the new location
}
Only thing i notice which is a problem is that the snap to grid stopped working with this function (i’m guessing the snap-to-grid is also a dragComputation function)
Thanks for the bug fixes. Actually, it would be better to check for Links by part instanceof go.Link rather than depending on the existence of Part.data and data.from.
Regarding grid snapping, use gridpt instead of pt.
It occurred to me that some people might prefer to keep a little space between nodes. That can be achieved with grid snapping, or by inflating the Rect r before calling isUnoccupied.