Auto Alignment of TextBlock at the center but within boundaries

NodeLabelDraggingTool.prototype.doMouseMove = function () {
  var pt = this.diagram.lastInput.viewPoint;
  var part = this.label.part;
  var g = part.containingGroup;
  if (g === null) return pt;  // allow top-level Nodes to move freely
  var b = part.actualBounds.copy();
  b.x += (pt.x - part.location.x);
  b.y += (pt.y - part.location.y);
  // OK to move if new location is still within the Group's SHAPE's polygonal Geometry
  if (GeometryHelper.shapeContainsRect(g.findObject("SHAPE"), b)) { this.label.part.location = pt };
  // otherwise leave the Node where it was
  this.label.part.location = part.location;
  this.updateAlignment();
}

It still does go outside. Are pt and part incorrect ? If yes, what should be the correction.

That doesn’t look right – isn’t this.label.part going to be the Group? Why do you care about part.containingGroup? Don’t you want this.label.getDocumentBounds()? Why are you adding the offset from the part.location? Do you really want to be setting the Group.location?

I made some corrections based on your suggestions, but if(GeometryHelper.shapeContainsRect(g.findObject("SHAPE"), b)) always gives false, also what property of this.label do I need to set and with what value ? Is the below correct ?

NodeLabelDraggingTool.prototype.doMouseMove = function () {
  var pt = this.diagram.lastInput.viewPoint;
  var part = this.label;
  var g = this.label.part;
  if (g === null) return pt;  // allow top-level Nodes to move freely
  var b = part.getDocumentBounds().copy();
  b.x += (pt.x - part.getDocumentBounds().x);
  b.y += (pt.y - part.getDocumentBounds().y);
  // OK to move if new location is still within the Group's SHAPE's polygonal Geometry
  if (GeometryHelper.shapeContainsRect(g.findObject("SHAPE"), b)) {
    this.label.alignment.x = pt.x;
    this.label.alignment.y = pt.y;
  } else {
    // otherwise leave the Node where it was
    this.label.alignment.x = part.getDocumentBounds().x;
    this.label.alignment.y = part.getDocumentBounds().y;
  }
  return NodeLabelDraggingTool.prototype.doMouseMove.call(this);
}

You don’t want to deal with viewport coordinates – only document coordinates.
Isn’t this.label the group’s textblock? Not a Part? So this.label.part is always the Group.
And you care about the area of the label, not the group.
Those offsets don’t make sense to me – step through the code and look at the values.

I’m asking all these questions so that you force yourself to understand the situation so that you can write the correct code. You should always be asking yourself questions to make sure you understand everything. If I just gave you the answer you wouldn’t be able to adapt the code and maintain it. Teach a man to fish | TechRepublic

I have almost corrected the above code, although I am unsure about the way to convert a Point to Spot, I saw one of earlier forums where you have done it, although I do not understand the logic, but tried to use…

NodeLabelDraggingTool.prototype.doMouseMove = function () {
  var pt = this.diagram.lastInput.documentPoint;
  var part = this.label; //textblock
  var g = this.label.part; //group
  var gArea = g.getDocumentBounds().copy();
  if (g === null) return pt;  // allow top-level Nodes to move freely
  var b = part.getDocumentBounds().copy();
  b.x = (pt.x);
  b.y = (pt.y);
  // OK to move if new location is still within the Group's SHAPE's polygonal Geometry
  if (GeometryHelper.shapeContainsRect(g.findObject("SHAPE"), b)) {
    this.label.alignment = new go.Spot(Math.max(gArea.x, Math.min(gArea.x, (pt.x - b.x) / (b.width || gArea.x))),
      Math.max(gArea.y, Math.min(gArea.y, (pt.y - b.y) / (b.height || gArea.y))));
  } else {
    // otherwise leave the Node where it was
    this.label.alignment = new go.Spot(Math.max(gArea.x, Math.min(gArea.x, 0)),
      Math.max(gArea.y, Math.min(gArea.y, 0)));
  }
  this.updateAlignment();
}

Can you advise ?

So if g is null, you call getDocumentBounds on it?
Spot.x and Spot.y are fractional values denoting a point in a rectangular area. That way if the shape/group changes size, the label will stay in the same relative place. So you have to make sure the x and y values you set for any Spot are between 0 and 1, inclusive.

Also, am I correctly updating the this.label.alignment to guide label position?

Besides the problem I already told you about? Maybe. I haven’t tried the code, so it’s hard to tell. But it should be clear when you run it.

Hi @walter,

I am OK with having to move the TextBlock even outside the group for now, but how can I fix the odd behavior when I move the TextBlock to left or top ?

node_move

Maybe you want to set the Node.locationSpot to go.Spot.Center.

while overriding the doMouseMove ?

No, permanently, in the template. Otherwise the node would appear to shift during the operation of that tool.

earlier my group had locationSpot: go.Spot.TopLeft
When I make my group to this -

 this.floorPlan.groupTemplate = $(
      go.Group,
      go.Group.Spot,
      {
        locationSpot: go.Spot.Center
      }

Now the same issue happens on all sides, it moves my group to the opposite side of what my label is being dragged.

Ah, right – your Group has no Placeholder. So you need to set Part.locationObjectName to refer to the object that you want to remain stabile. Probably the polygonal Shape. Whereas the dragged TextBlock is mobile and thus must not be in the Part.locationObject.

Thanks, I fixed it with

this.floorPlan.groupTemplate = $(
      go.Group,
      "Spot",
      {
        layerName: "BlockLayer",
        locationSpot: go.Spot.Center,
        locationObjectName: "SHAPE"
      },

Although I still need to look at how the label be restricted to move only inside the group, but could not basically come up with how to calculate spot.x and spot.y as you say. Will give it one more try later.