How to restrict an object /node within given area

How to restrict object dragged from palette within four line drawn as in the image?

I suppose you could implement an “ExternalObjectsDropped” DiagramEvent listener that looks at the actualBounds of each dropped Node in the Diagram.selection. If it is within the desired area, all is well. If not, you can either move the node to make it valid or you could cancel the drop by calling myDiagram.currentTool.doCancel().

If lines are not selected then how i will do it? And once the node is dropped it should not be draggable outside these four lines?

You’ll need to decide what area(s) to consider – we cannot make that policy decision for you, so that such areas are not determined by which parts are selected.

You’ll want to implement a Part.dragComputation function: Part | GoJS API. See also the documentation for: DraggingTool | GoJS API

Hi walter thank you for the response.
Can you help me out how can i combine stayInViewport and avoidNodeOverlap function so that i can get the combine output of both the function.
As we can only use one function on Part.dragComputation.

function stayInViewport(part, pt, gridpt) {
var diagram = part.diagram;
if (diagram === null) return pt;
// compute the area inside the viewport
var v = diagram.viewportBounds.copy();
v.subtractMargin(diagram.padding);
// get the bounds of the part being dragged
var b = part.actualBounds;
var loc = part.location;
// now limit the location appropriately
var x = Math.max(v.x+1, Math.min(pt.x, v.right-b.width-2)) + (loc.x-b.x);
var y = Math.max(v.y+1, Math.min(pt.y, v.bottom-b.height-2)) + (loc.y-b.y);
return new go.Point(x, y);
}

function avoidNodeOverlap(node, pt, gridpt) {
// this assumes each node is fully rectangular
var bnds = node.actualBounds;
var loc = node.location;
// see if the area at the proposed location is unoccupied
// use PT instead of GRIDPT if you want to ignore any grid snapping behavior
var x = gridpt.x - (loc.x - bnds.x);
var y = gridpt.y - (loc.y - bnds.y);
var r = new go.Rect(x, y, bnds.width, bnds.height);
// maybe inflate R if you want some space between the node and any other nodes
if (isUnoccupied(r.inflate(-1, -1), node)) return gridpt; // OK
return loc; // give up – don’t allow the node to be moved to the new location
}

As i have two requirements
1.object should not overlap
2.object can not be dragged outside of specified are

Yes, you need to combine the restrictions into one function.

Hi walter ,

I am not able to combine these two fucntion to get desired output.
Can you help me out with that?

Following are the two function

stayInViewport

function stayInViewport(part, pt, gridpt) {
var diagram = part.diagram;
if (diagram === null) return pt;
// compute the area inside the viewport
var v = diagram.viewportBounds.copy();
v.subtractMargin(diagram.padding);
// get the bounds of the part being dragged
var b = part.actualBounds;
var loc = part.location;
// now limit the location appropriately
var x = Math.max(v.x+1, Math.min(pt.x, v.right-b.width-2)) + (loc.x-b.x);
var y = Math.max(v.y+1, Math.min(pt.y, v.bottom-b.height-2)) + (loc.y-b.y);
return new go.Point(x, y);
}


avoidNodeOverlap

function avoidNodeOverlap(node, pt, gridpt) {
// this assumes each node is fully rectangular
var bnds = node.actualBounds;
var loc = node.location;
// see if the area at the proposed location is unoccupied
// use PT instead of GRIDPT if you want to ignore any grid snapping behavior
var x = gridpt.x - (loc.x - bnds.x);
var y = gridpt.y - (loc.y - bnds.y);
var r = new go.Rect(x, y, bnds.width, bnds.height);
// maybe inflate R if you want some space between the node and any other nodes
if (isUnoccupied(r.inflate(-1, -1), node)) return gridpt; // OK
return loc; // give up – don’t allow the node to be moved to the new location
}

As i have two requirements
1.object should not overlap
2.object can not be dragged outside of specified are

What have you tried, and why does it not behave the way that you want?

function stayInViewport(part, pt, gridpt) {
var diagram = part.diagram;
if (diagram === null) return pt;
// compute the area inside the viewport

var v=diagram.fixedBounds.copy();
v.subtractMargin(diagram.padding);
var b = part.actualBounds;
var loc = part.location;
// get the bounds of the part being dragged
var x = gridpt.x - (loc.x - b.x);
var y = gridpt.y - (loc.y - b.y);
var r = new go.Rect(x, y, b.width, b.height);




// now limit the location appropriately
var xa = Math.max(v.x+1, Math.min(gridpt.x, v.right-b.width-1)) + (loc.x-b.x);
var ya = Math.max(v.y+1, Math.min(gridpt.y, v.bottom-b.height-1)) + (loc.y-b.y);

if(gridpt.x<0 && xa<0 && gridpt.x>v.x){
var newXa=Math.min(gridpt.x,xa);
} if(gridpt.x>0 && xa>0 && gridpt.x>v.x && gridpt.x<(v.x+v.width)){
var newXa=Math.min(gridpt.x,xa);
}else if(gridpt.x<0 && xa >0 && gridpt.x>v.x && gridpt.x<(v.x+v.width)){
var newXa=Math.min(gridpt.x,xa);
}else if(gridpt.x>0 && xa<0){
var newXa=Math.max(gridpt.x,xa);
}

if (isUnoccupied(r.inflate(-2, -2), part)) return new go.Point(newXa,Math.min(ya,gridpt.y)); // OK
//else return loc;
return new go.Point(Math.min(xa,loc.x),Math.min(ya,loc.y));

}

this is what i have tried but havent got the desired output.
Can you please suggest some way.
Following are the two condition what are reuired
1.object should not go beyond the four walls.
2.object should not overlap

for 1.condition i have used fixed bounds so that i can resrict object within four lines.
but 2nd condition i am not able to achieve together with 1st condition.

    // 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 and any Links
      function navig(obj) {
        var part = obj.part;
        if (part === node) return null;
        if (part instanceof go.Link) 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) {
      if (node.diagram instanceof go.Palette) return gridpt;
      // compute the area inside the viewport
      var v = node.diagram.viewportBounds.copy();
      v.subtractMargin(node.diagram.padding);
      // get the bounds of the part being dragged
      var b = node.actualBounds;
      var loc = node.location;
      // now limit the location appropriately
      var x = Math.max(v.x + 1, Math.min(pt.x, v.right - b.width - 2)) + (loc.x - b.x);
      var y = Math.max(v.y + 1, Math.min(pt.y, v.bottom - b.height - 2)) + (loc.y - b.y);
      var r = new go.Rect(x - (loc.x - b.x), y - (loc.y - b.y), b.width, b.height);
      // maybe inflate R if you want some space between the node and any other nodes
      r.inflate(-0.5, -0.5);  // by default, deflate to avoid edge overlaps with "exact" fits
      // when dragging a node from another Diagram, choose an unoccupied area
      if (!(node.diagram.currentTool instanceof go.DraggingTool) &&
          (!node._temp || !node.layer.isTemporary)) {  // in Temporary Layer during external drag-and-drop
        node._temp = true;  // flag to avoid repeated searches during external drag-and-drop
        while (!isUnoccupied(r, node)) {
          r.x += 10;  // note that this is an unimaginative search algorithm --
          r.y += 10;  // you can improve the search here to be more appropriate for your app
        }
        r.inflate(0.5, 0.5);  // restore to actual size
        // return the proposed new location point
        return new go.Point(r.x - (loc.x - b.x), r.y - (loc.y - b.y));
      }
      if (isUnoccupied(r, node)) return new go.Point(x, y);  // OK
      return loc;  // give up -- don't allow the node to be moved to the new location
    }

Thanks walter.
When i use the above function it move the object when dragged from palette to random location on some occasion even if there is unoccupied space.

Where would you want the temporary node to be positioned during a drag when the mouse/finger does not move to a permitted point? And might never do so?

when there is unoccupied space/point where node can be dragged it should allow.
But if the spaced is occupied it should keep the object to unoccuiped place.

Where should it find such a spot? What if there is no such spot?

Within those four line it should find such spot.If there is no such spot within four line it should not allow to drop.

The basic problem is that until the node exists, there is now way to tell how big it is, and thus no way to decide if it might fit in some spacd.