Prevent node exceeding group's boundaries

I have a map that looks like this:

As you can see the nodes exceed their group’s boundaries.

How can I prevent that?
Here is my code:

 this.diagram.nodeTemplate =
            $(go.Node, "Auto",
                {locationSpot: go.Spot.Center, selectionAdorned: false,dragComputation: this.avoidNodeOverlap},
                $(go.Panel, "Auto",
                    {name: "PANEL"},
                    new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                    $(go.Shape, "Rectangle",  // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            fromLinkable: false, toLinkable: false, cursor: "pointer",
                            strokeWidth: 3,
                        },
                        new go.Binding("stroke", '', (n) => {
                            return n.isActive ? 'yellow' : n.stroke;
                        }),
                        new go.Binding("fill", '', (n) => {
                            return n.highlight || n.isActive ? n.stroke : n.fill;
                        }),
                        new go.Binding("figure")),
                    $(go.TextBlock,
                        {margin: 10, font: "bold 32px sans-serif", cursor: "pointer"},  // some room around the text
                        new go.Binding("text", "text"),
                        new go.Binding("stroke", '', (n) => {
                            return n.isDarkFill ? 'white' : 'black';
                        })),
                    {
                        contextClick: (e, node) => {
                            if (!this.props.userMaps.currentMap.literature.isHeatmap) {
                                this.props.nodeRightClick(node.part.data, e.viewPoint);
                            }
                        },
                    }
                ));

this.diagram.groupTemplate =
            $(go.Group, "Auto",
            new go.Binding("", "display", (display, graphObj) => {
                graphObj.setProperties(display.layout);
            }),
                $(go.Panel, "Auto",
                    $(go.Shape, "Ellipse",
                        {
                            name: "OBJSHAPE",
                            parameter1: 14,
                            margin: new go.Margin(50, 0, 0, 0)
                        },
                        new go.Binding("fill", "fill"))
                ),
                $(go.Panel, "Vertical",
                    $(go.Panel, "Spot",
                        { isClipping: true, stretch: go.GraphObject.Horizontal, height: 200 },
                        new go.Binding("visible", "display", (display) => display !== undefined),
                        $(go.Shape,
                            new go.Binding("", "display", (display, graphObj) => {
                                graphObj.setProperties(display.shape);
                            }),
                        ),
                        $(go.Picture,
                            new go.Binding("source", "display", (display) => display.img),
                        ),
                        $(go.TextBlock,
                            {
                                name: "GROUPTEXT",
                                alignment: go.Spot.Center,
                                // alignmentFocus: new go.Spot(0, -2, 0, 0),
                                font: "Bold 32px Sans-Serif",
                                stroke: "white"
                            },
                            new go.Binding("text", "text")),
                    ),
                   
                    $(go.Placeholder, { padding: 48 }),
                ),
                
            );

Which nodes exceed their containing group’s boundaries? I don’t see any.

But perhaps you are referring to some of the member nodes not being within the elliptical shape that the group has.

First, the “Auto” Panel surrounding the “Ellipse” Shape seems completely superfluous. Just delete that Panel and use the Shape there as the first element of the Group.

Hmmm, maybe that’s all you need. Having the “Ellipse” Shape as the main element of the “Auto” Panel Group will cause the second element to be fit into the rectangular area of the ellipse that is completely enclosed by the ellipse. Oh, you shouldn’t need to specify the padding on the Placeholder then. Or at most a smaller distance.

On an unrelated issue – why not set a maxSize width on the TextBlock in your node template? It’s hard to read long text without wrapping.

Thanks. It helped but now the other shape - the one containing the Picture is inside the ellipse and I need it to be on top of it.
When I set the margin of this shape to be minus 100 (for instance) it overflows the ellipse and looks like this:
Screenshot%20from%202019-07-14%2017-16-33

It’s unclear what you want. You need to use some kind of Panel to hold your Picture and TextBlock. Learn how to use panels: https://gojs.net/latest/intro/panels.html and https://gojs.net/latest/intro/panels.html

I want something like discussed here: https://stackoverflow.com/questions/40810102/having-visible-overflow-inside-of-a-gojs-node-or-graphobject.
The Gate shape should be on top of the ellipse and the ellipse should contain all child nodes without them exceeding its boundaries.

It is very unusual to use a negative Margin.

I think you want something like:

Group, "Vertical"
    Shape or Picture (showing a gate)
    Panel, "Auto"
        Shape, "Ellipse"
        Placeholder

Thanks. Now I’m asked to show a picture as a background of the ellipse.
All nodes must be inside the ellipse ( the user will see only the picture and the background of the ellipse will be transparent) and the picture should take all of the node’s space.
What I have now is this:


I used a HalfEllipse and a purple picture inside it.

I also need to position two nodes in a specific location. One at the bottom and ane on the top area.
My code:

 this.diagram.groupTemplate =
            $(go.Group, "Auto",
                new go.Binding("", "display", (display, graphObj) => {
                    graphObj.setProperties(display.properties);
                }),
                $(go.Shape, "Ellipse",
                    {
                        name: "OBJSHAPE",
                        parameter1: 14,
                    },
                    new go.Binding("fill", "fill"),
                    new go.Binding("", "display", (display, graphObj) => {
                        graphObj.setProperties(display.shape);
                    }),
                ),
                $(go.Placeholder,
                    { padding: 48 }),
                $(go.Picture, { name: "PICTURE", imageStretch: go.GraphObject.Fill, column: 0 },
                    new go.Binding("source", "display", (display) => display.img),
                ),
                $(go.TextBlock,
                    {
                        name: "GROUPTEXT",
                        alignment: go.Spot.TopLeft,
                        alignmentFocus: new go.Spot(0, 0, -4, -4),
                        font: "Bold 32px Sans-Serif",
                        stroke: "white"
                    },
                    new go.Binding("text", "text")
                ),

            );

And the positioning code where I also tried to set the picture’s size:

this.diagram.addDiagramListener("InitialLayoutCompleted",(e)=>this.recalculateNodesPosition(subcellularLocations));
this.diagram.addDiagramListener("SelectionMoved",(e)=>this.recalculateNodesPosition(subcellularLocations));

recalculateNodesPosition = (subcellularLocations) => {
     this.diagram.nodes.each(node => {
            const subcellularLocation = subcellularLocations.find(loc => "sl_" + loc.id === node.key);
            if (subcellularLocation && SubcellularLocationInfo[subcellularLocation.name]) {
                const layout = SubcellularLocationInfo[subcellularLocation.name].layout;
                const size = layout.size(node.diagram);

                node.desiredSize = new go.Size(size.width, size.height);

                const picture=node.findObject("PICTURE");
            
                if(picture){
                    picture.width=size.width;
                    picture.height=size.height;
                }
               
                const position = layout.position(node.diagram, node);
                node.move(new go.Point(position.x, position.y));
            }
            else{
                /****** prevent groups overlapping  - not really working *****/

                // var bnds = node.actualBounds;
                // var loc = node.location;
                // const r=node.actualBounds;
                //   while (!this.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
                //   node.move(new go.Point(r.x - (loc.x - bnds.x), r.y - (loc.y - bnds.y)));
                
               
            }
        });
    }

Thanks a lot for your patience and help!

It is the Group.layout that is responsible for arranging the group’s member nodes and links. You might want to use https://gojs.net/latest/api/symbols/PackedLayout.html . Try it out at https://gojs.net/latest/extensions/PackedLayout.html.

But I don’t need a special layout I just want the picture to take all of the group’s space as a background and the nodes will be as they are now (as they look in the other groups).

Also the positioning is not working as smoothly as I expect - do you have any suggestions for that?

I still do not understand exactly what you want. Have you tried this kind of group template?

Group, "Auto"
    Picture
    Placeholder

A post was split to a new topic: Moving nodes sequentially