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:
$(go.Node, . . .,
{ dragComputation: avoidNodeOverlap },
. . .
)