SVG image resizing inside the panel

Greetings!
I’m currently investigating the possibility of reusing one of our internal libraries, built with GoJS, for a new project. The main question is, “Can we enable icon resizing without major rework on the existing functionality”. I have tried experimenting with the existing code but didn’t manage to get any satisfactory results. quite possible, that it’s indeed not possible with the current structure. So, what we have at the moment:

This is the code, used to generate the element:

    const node = $(go.Node, 'Spot',
      new go.Binding('location', 'position', go.Point.parse),
      {
        // Have added 'resizable' here, trying to get something resizable
        resizable: true,
        locationObjectName: 'mainRectangle', locationSpot: go.Spot.Center

        // some code to handle mouse enter/leave events to show/hide the ports, as well as connecting/disconnecting
      },
      $(go.Panel, 'Auto',
        $(go.Shape, 'RoundedRectangle', {
          fill: uiTheme.puBackground,
          parameter1: 2,
          minSize: new go.Size(140, 44),
          maxSize: new go.Size(180, 44),
          name: 'mainRectangle',
          cursor: 'grab'
        }),
        $(go.Panel, 'Horizontal', {alignment: go.Spot.Left},

          //! This is the element I would like to enable for resizing - the icon itself

          $(go.Picture, {
            name: 'ICON_IMAGE',
            margin: new go.Margin(8, 10, 8, 12),
            desiredSize: new go.Size(28, 28),
            cursor: 'grab'
          },
            new go.Binding('source', 'typeDef', (t) => t.imageSrc)),
          $(go.Panel, 'Vertical', {margin: new go.Margin(0, 12, 0, 0)},
            $(go.TextBlock, {
              name: 'SERIAL_TEXT',
              margin: new go.Margin(0, 0, 3, 0),
              alignment: go.Spot.Left,
              stroke: uiTheme.font,
              maxSize: new go.Size(118, 600),
              overflow: go.TextBlock.OverflowEllipsis,
              maxLines: 1,
              font: '500 12px Roboto',
              cursor: 'grab'
            },
              new go.Binding('text', 'serial')),
            // plus one more text block
          )
        )
      ),
      //PORTS
      $(go.Panel, 'Vertical', {alignment: go.Spot.Left},
        new go.Binding('itemArray', 'leftPorts'),
        {
          itemTemplate:
            $(go.Panel, 'Auto',
              $(go.Shape, 'Rectangle', {
                desiredSize: new go.Size(12, 12),
                opacity: 0,
                margin: new go.Margin(1, 0, 1, 0)
              }),
              $(go.Shape, 'circle',
                {
                  strokeWidth: 1,
                  desiredSize: NodeTemplates.portCircleSize,
                  stroke: null,
                  visible: true,
                  fill: null,
                  fromLinkable: true,
                  toLinkable: true,
                  toMaxLinks: 1,
                  fromMaxLinks: 1,
                  fromSpot: go.Spot.Left,
                  toSpot: go.Spot.Left
                },
                new go.Binding('portId', 'id')
              )
            )
        }
      ),
      // plus 3 more panels with parts on the right, top, and bottom
    );

    return node;

I’ve managed to achieve resizing with the following approach:

    const node = $(go.Node, 'Spot',
      {
        resizable: true,
      },
      $(go.Panel, 'Auto',
        $(go.Picture, {
          name: 'ICON_IMAGE',
          cursor: 'grab',
        },
          new go.Binding('source', 'typeDef', (t) => t.imageSrc)),
      ),
    );

Can I get the same icon behavior, but being located deep inside those panels?

I’m trying to reproduce your situation, but am unable to do so because I cannot tell what it is that you want to resize. If you want the user to resize the Picture named “ICON_IMAGE”, just set Part.resizeObjectName to that name:

  $(go.Node, 'Spot',
      new go.Binding('location', 'position', go.Point.parse),
      {
        // Have added 'resizable' here, trying to get something resizable
        resizable: true, resizeObjectName: "ICON_IMAGE",
        . . .

If you don’t want the user from resizing that Picture directly, then you could have them resize one of its containing panels. But you will need to make sure that the Picture and any Panels between the Picture and the resized Panel are stretched appropriately so that the contents of the panel adjust their sizes the way that you want.

Oh, thank you so much! It’s exactly what I need!

Have another question, not sure how to ask it properly, but will try anyway)) Which property is responsible for the size of this icon? I mean, before, we used to save only x and y coordinates in the model, as all the blocks were the same size.

{
  "blocks": [
    {
      "id": "b1",
      "coords": {
        "x": 632,
        "y": 708
      },
      "serialNumber": "000-000",
      "type": 7,
      "typeName": "Compressor",
      "isLinked": false,
      "objectType": "ProcessUnit"
    }
  ]
}

Now I’ll need to save the size of the icon as well, to reproduce the saved diagram later. I understand that you are not aware of our library’s inner structure, but perhaps you know how it could be achieved…

Whichever element is being resized by the ResizingTool, which is the Part.resizeObject that is identified by the optional Part.resizeObjectName, should have a TwoWay Binding on it:

  new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)

Here I have assumed that the name of the data property is “size” and that it is of type string, but of course you can choose whatever property name that you like.