Disable overlap of nodes

Hi,

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)

Is there a default functionality to do so?

Tim

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 },
        . . .
    )

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.

awesome, thanks.

Unfortunately i didn’t think this all the way thru, so a can’t implement it as it is atm, but in the future this will definitely be helpfull!

See the new sample Drag Unoccupied