Adornment resizing

Is it possible to resize an adornment depending on the size on the size of a node? I am asking because I have node with a go.Picture element that changes size when the picture changes.
This is the adornment code:

$(go.Adornment, 'Auto',
        {
            layerName: 'Background',
            selectable: false,
            isInDocumentBounds: false
        },
        new go.Binding('desiredSize', '', function (data, adornment) {
        
             console.log(adornment.canResize())
             let node = adornment.adornedObject;
        
             let currentBounds = node.data.category !== 'image' ? node.actualBounds :
                 node.findObject('PIC').actualBounds;
        
             return currentBounds.width > 100 && currentBounds.height > 100 ?
                 new go.Size(currentBounds.width + 10, currentBounds.height + 10) :
                 new go.Size(100, 100);
         }),
        new go.Binding('visible', '', function (data, adornment) {

            let node = adornment.adornedObject;

            return node.isVisible();
        }),
        getShape(node, color),
        $(go.Placeholder)

When I try to use the above code, I get the follwing warning:

Change not within a transaction: !d desiredSize: Adornment(Background)Node#3970(image) old: Size(100,100) new: Size(610,410)

Are you talking about a Part.selectionAdornmentTemplate?

The basic problem is that you’ve put it into the “Background” layer. By default they go into the “Adornment” layer, which is a temporary layer (Layer.isTemporary) that causes all changes to objects in that layer to be ignored by the UndoManager.

If you want to make the border object (the main object of the “Auto” Panel) bigger, just increase the margin on the Placeholder.

There is also no need to try to bind its visible property.

Something like this should work:

      $(go.Node, . . .,
        {
          selectionObjectName: "PIC",
          selectionAdornmentTemplate:
            $(go.Adornment, "Auto",
              $(go.Shape, { fill: null, stroke: "cyan", strokeWidth: 4 }),
              $(go.Placeholder, { margin: 2 })
            )
        },
        . . .
    )

Hi walter,
I am adding the adornments programatically by some specific condition. I also have node templates defined over several files, so defining adornment templates separately seemed like a good idea. I thenn simply add them via addAdornment method when I need them, and remove via removeAdornment method when I am done with them.
Hence, I need to put them in the background layer, because otherwise they appear over the node, instead of behind them. I also don’t want the adornment to become visible on selection, only on my condition which is defined programatically (as I mentioned).

Ah, OK, that makes sense then.

I suggest that you create a new Layer for your background adornments. Something like:

myDiagram.addLayerBefore($(go.Layer, { name: "BackgroundAdornment", isTemporary: true }),
                         myDiagram.findLayer("Background"))

and change your Adornment.layerName accordingly.

When you create one of your adornments, do you set Adornment.adornedObject to the particular object in your node that you want to be adorned? (That might be the whole Node.) That way the Placeholder in your Adornment will automatically get the size of that object, and you can define your Adornment panel based on that Placeholder. You should not need the bindings that you have defined.

Thanks walter, the warning is gone now.
Yeah, I do, like this:

    diagram.startTransaction(adornmentTransactions.adornNode);
    adornment.adornedObject = node;
    node.addAdornment(category, adornment);
    diagram.commitTransaction(adornmentTransactions.adornNode);

I’m not completely understand what you mean by this: " you can define your Adornment panel based on that Placeholder. ". Can I get a link to an example maybe?
“That way the Placeholder in your Adornment will automatically get the size of that object,” - for some nodes I feel that the adornment is too big, that’s why I wanted to bind to the desiredSize and attempt to resize it manually.

Any Adornment that has a Placeholder will be positioned so that the Placeholder is where the Adornment.adornedObject is.

So I was suggesting that you set adornedObject to node.findObject("PIC").

But I’m just guessing what you might want.

I think the main issue is that binding to DesiredSize doesn’t change the size of the adornment. The function defined in the binding gets called twice - once while the size of the node is, e.g. 100, 100, and the second when it’s 640, 400. However, the size of the adornment doesn’t change - when I have this binding set, which I would like to have, in order to adjust the size.
I am aware, that the placeholder automatically adjusts the size.

On a somewhat unrelated note… if you could also tell me… when I set the minSize for the go.Picture element that is part of a go.Node to 50x50 (new go.Size(50, 50), the node appears as a 50x50 node… however, when I specify the maxSize to new go.Size(640,400) for the same go.Picture object, the node gets stretched to full size. The element is held in a palette. I’d like it to appear as a 50x50 node in the palette… But also, when I drop it to a diagram, I’d like it to be resized according to the image size.

I just tried your code, and the desiredSize Binding seems to work as I would expect from reading your code.

I still think you can get what you want without that Binding, just by specifying a minSize on the Adornment and a margin on the Placeholder.

And I don’t think you need the binding on visible either.

For your other question, I suggest that you use different templates. GoJS Palette -- Northwoods Software

This is the image node template:

$(go.Node, 'Spot', {

                locationSpot: go.Spot.Center,
                locationObjectName: 'BODY',
                dragComputation: draggingFunctionsProvider.stayInGroup
            },
            $(go.Panel, 'Auto',
                $(go.Shape, shape, nodeShapeSettings(fillColor)),
                $(go.Picture, {
                        name: 'PIC',
                        background: 'white',
                        margin: 10,
                        minSize: minSize
                    },
                    new go.Binding('source', 'value'))
            ),
            getPort(portTypes.input),
            $(go.TextBlock, {

                    editable: false,
                    margin: 2,
                    visible: true,
                    alignment: go.Spot.Bottom
                },
                new go.Binding('text', 'description')
            ))

Thanks walter, but I want to limit the maximum size of the adornment, not minimum.

I need the binding to visible because I want to hide the adornments in case an element is inside a collapsed group.

That’s not what your code does:

But you can do what you want. When I tried your code, it was correctly setting the Adornment.desiredSize to be bigger than it needed to be when the “PIC” element was smaller than 100x100, or a little bigger than the adornedObject when it was greater than 100x100 in both directions.

Sorry walter, you were right, it does work.
Thanks for your help!

May I just return to the previous question regarding minSize and maxSize… how can I prevent the node from being enlarged when its dragged from a palette to a diagram?
I want the desiredSize to adjust depending on the picture loaded.

The basic answer is to set the Picture.desiredSize. That will ensure that the node will always be the same size.

I do hope you have read GoJS Pictures -- Northwoods Software. As it demonstrates, there are many different ways that you can control the size of the image, both sizing and stretching. And there is also using a “Viewbox” Panel: GoJS Panels -- Northwoods Software.

Since I don’t understand both the details of your situation and the details of what you want, it’s hard for me to do anything but guess at how to accomplish what you want.

I have set two templates for a node - one template for palette and another for the diagram.
When I drag the node from the palette to the diagram, the node gets enlarged. This is probably due to the panel filling up available space up to the set of maxSize.
I don’t want to hardcore the desiredSize because I want the node to resize depending on the picture loaded :-)

OK, so you have slightly conflicting requirements. You want the Picture to have different sizes, based on the image’s natural size, but you want your Node in the main Diagram to have the same size no matter what, but you want the corresponding Node in the Palette to have a particular fixed size. Is my understanding basically correct?

If so, it seems to me that nodes will always change size as you drag them from the Palette to the main Diagram.

Maybe you could choose a maxSize that is similar to the size that you use in the Palette? Or maybe you could change the Diagram.initialScale for the Palette so that it matches what happens in the Diagram?

Basically correct:

  • I want the picture to have different sizes, based on the image’s natural size - correct
  • “but you want your Node in the main Diagram to have the same size no matter what” - no, I just want its size to be equal to the size in the palette when it is initially dropped - before I set the source.
  • “you want the corresponding Node in the Palette to have a particular fixed size” - correct.

I’m thinking of just setting a desiredSize to something reasonable and to allow the user to resize the node if he wishes.

Is the reason that the node in the target diagram might be a different size than the one in the palette because the Picture.source might be different, and thus the size or aspect ratio of the image is different than in the palette?

If you used the same templates in both palette and diagram and they were bound to the same data, they should have the same size.

No source is set in the palette, just the minSize… and no source is set on the target diagram, but minSize and maxSize are set… since I set the maxSize on the diagram, I assume something is stretching the node. Or is my assumption incorrect?

If you use exactly the same templates with the same data, they should appear the same in both diagrams.

It isn’t clear to me why setting maxSize would cause a node to increase in size.

I can confirm the commenting out maxSize in the diagram template, prevents the diagram from enlarging the node :-)
Perhaps some panel enlarges the node? I’m really not sure…