Problem with resize and minSize width

I think I may have discovered a bug with the minSize and textBlocks. We are making a “notes” node type in which people can type in a note and move it and resize it anywhere on their map.
When I set the minSize on the Node element, I am not able to set the textBlock to a smaller width than the Node’s set width. The height setting doesn’t seem to have an issue, only width. Is this a bug in the framework?

Here’s a gif of the issue:

Here’s the code for the Node type. Changing the Node’s minSize width to “NaN” fixes the issue.


noteNodeTemplate = _self._go(go.Node, "Spot",{
		isLayoutPositioned: false,
		layerName: "Notes",
		movable: false,
		selectionAdorned: false,
		location: new go.Point( -50, -50 ),
		minSize: new go.Size( 270, 200 ),
		
        resizable: true, 
        resizeAdornmentTemplate:
            _self._go(go.Adornment, "Spot",
                _self._go( go.Placeholder ),
                _self._go( go.Panel, {
    				alignment: new go.Spot( 1, 1, -15, -15 ),
    				cursor: "pointer",
    				name: "resizeHandle"
    			},
    			_self._go(go.Shape, { 
    				alignment: new go.Spot( 0.5, 0.5 ),
    				height: 30, width: 30,
    				fill: "transparent", 
    				strokeWidth: 0
    				}
                ),	
    			_self._go( go.Shape, { 
    				strokeWidth: 0, fill: "#8a8a8a", 
    				alignment: new go.Spot( 0.5, 0.5 ),
    				geometryString: go.Geometry.fillPath( "M14.47 13.06 10.94 9.53 9.53 8.12 11.64 6 6.01 6.01 6 11.64 8.12 9.53 9.53 10.94 13.06 14.47 14.47 15.88 12.36 17.99 17.99 17.99 18 12.36 15.88 14.47 14.47 13.06" )
                })
			)
        )
	},
	
	_self._go(go.Shape, { 
		alignment: new go.Spot( 0.5, 0.5 ),
		name: "BODY",
		height: 100, width: 160,
		fill: "#ffffff", 
		strokeWidth: 2,
		strokeDashArray: [6, 4],
		stroke: "#8a8a8a"
		},
		new go.Binding( "height", "height", function( val, obj ) {
			return ( +val - 3 );
		}),
		new go.Binding( "width", "width", function( val, obj ) {
			return ( +val - 3 );
		})
    ),
    
    
    _self._go(go.TextBlock, { 
	    alignment: new go.Spot(0, 0, 20, 10),  
		name: "textBlock",
		stroke: '#8a8a8a',
		cursor: 'text',
		background: 'blue',
		text: "test this text",
		font: '16px sans-serif',
		editable: true,
		textEdited: function( obj, prevText, newText ) {
			
			if ( newText == "" ) {
				obj.text = $l( 'Body of the note goes here' );
			}
		}},
		new go.Binding( "height", "height", function( val, obj ) {
			var currAlignment = obj.alignment;
			
			obj.alignment = new go.Spot( currAlignment.x, currAlignment.y, currAlignment.offsetX, ( val / 2 ) );
			
			return ( +val - 60 ); // subtract to provide padding
		}),
		new go.Binding( "width", "width", function( val, obj ) {
			var currAlignment = obj.alignment;
			
			obj.alignment = new go.Spot( currAlignment.x, currAlignment.y, ( val / 2 ), currAlignment.offsetY );
			
			return ( +val - 20 ); // subtract to provide padding
		})
		
    ),
    
	new go.Binding( "height", "height").makeTwoWay(),
	new go.Binding( "width", "width").makeTwoWay(),
	new go.Binding("location", "_location", go.Point.parse ).makeTwoWay( go.Point.stringify )
);

As GoJS Tools -- Northwoods Software discusses, I think you don’t want to be resizing the whole Spot Panel, but only some smaller piece of it. What is it that whose size you really want to control? Perhaps just the TextBlock itself?

If so, name that object, refer to it by setting Part.resizeObjectName, and transfer the width and height Bindings and any size constraints to that object.

In any case, it doesn’t make sense to try to set the width or the height of both a nested object and its containing panel to the same value!

Hey Walter,

I didn’t set the Part.resizeObjectName intentionally so that the resize target is the Node object (as per the docs). Then I set the width and height bindings to be two-way so that resizing sets the node’s data.
Then the textBlock and background shape are listening to the width and height data properties and setting their size to be slightly smaller (not the same!) than the containing node.

The issue comes when I’m trying to set a minSize on the node. The textBlock is not allowing me to set it’s width any smaller than the Node’s set minSize width. This really seems like a bug…

Also if I change the textBlock to be a Shape object, the issue goes away and works as expected.

Nesting the textBlock in a Panel with “Auto” positioning seems to fix the issue. I still think this is a bug.

Thanks!

Ah, yes, that binding uses a slightly smaller value for the width and height.

Still, it really ought to be the case that there’s a single GraphObject that the user resizes and that then determines the size of everything else that depends on it. You shouldn’t be binding the size of objects based on some calculation on the size. (Well, there can be exceptions, but it’s rare.) The reason is that those calculations might be (or become) wrong due to however the panels are defined.

And it’s even worse to modify other properties in a binding conversion function. It might sometimes work, but changing other object properties could result in undefined behavior. In your case maybe you just want to bind the GraphObject.alignment property.

I tried your suggestion of binding to the alignment property and removing the alignment assignments in the width/height bindings and still got the same behavior.

Are textBlocks expected to inherit the minSize width of the parent Node? That is what seems is happening.



_self._go(go.TextBlock, {   
    alignment: new go.Spot(0, 0, 20, 10),
	name: "textBlock",
	stroke: '#8a8a8a',
	cursor: 'text',
	background: 'red',
	editable: true,
	textEdited: function( obj, prevText, newText ) {
		
		if ( newText == "" ) {
			obj.text = $l( 'Body of the note goes here' );
		}
	}},
	new go.Binding( "text", "note" ),
	new go.Binding( "font", "font" ),
    new go.Binding( "height", "height", function( val, obj ) {
		return ( +val - 60 );
	}),
	new go.Binding( "width", "width", function( val, obj ) {
		return ( +val - 20 );
	}),
	new go.Binding( "alignment", "desiredSize", function( val, obj ) {
		var currAlignment = obj.alignment,
		    height = obj.part.height,
		    width = obj.part.width;
		
		return new go.Spot( currAlignment.x, currAlignment.y, ( width / 2 ), ( height / 2 ) );
	}).ofObject()
),

I do not believe that GraphObject.minSize is inherited from any containing Panel.

Perhaps I could try it if you could provide a node template that does not modify any properties in a binding conversion function.

Hey Walter,
I’d be happy to do that, but the whole point of this issue is that the conversion functions aren’t being respected, so it wouldn’t make sense to provide an example without them.

I’ve found a satisfactory workaround for this issue and I’m just trying to be helpful by reporting a bug. It’s hard for me to understand how this is expected behavior since it is ONLY happening with the width and not height on textBlocks.

Except for the custom resize adornment, doesn’t this operate the way that you want, but much simpler?

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        {
          isLayoutPositioned: false,
          layerName: "Notes",
          movable: false,
          selectionAdorned: false,
          location: new go.Point( -50, -50 ),
          minSize: new go.Size( 270, 200 ),
          resizable: true
        },
        new go.Binding("height").makeTwoWay(),
        new go.Binding("width").makeTwoWay(),
        new go.Binding("location", "location", go.Point.parse ).makeTwoWay( go.Point.stringify ),
        $(go.Shape,
          {
            fill: "#ffffff",
            strokeWidth: 2,
            strokeDashArray: [6, 4],
            stroke: "#8a8a8a"
          }),
        $(go.TextBlock,
          {
            margin: new go.Margin(20, 10), stretch: go.GraphObject.Fill,
            stroke: "#8a8a8a",
            cursor: "text",
            background: "blue",
            text: "test this test",
            font: "16px sans-serif",
            editable: true
          },
          new go.Binding("text").makeTwoWay())
      );

It turns out there is a bug here, thanks for reporting it.

TextBlocks try to respect the max size of their panel element, because that space influences when the TextBlock will wrap, but they were mistakenly also respecting the min size of their parent element, which should not affect the size of the TextBlock.

This will be fixed in the next release.

We just released 1.7.22, which has a fix for this.

Wow, you guys are awesome! Thank you so much :)