Overlapping a geometryString

Hello!

I’m having some problems creating a geometryString wich overlap another geometryString.

I have a Node with ports wich have a geometryString figure, I need to overlap this figure with another one in some cases (with a fill color and stroke color).

Here is my definition of the nodeTemplate:

    templateMap.add('geometryWithLabel',
        $(go.Node, this.nodeStyle(this.configuratorService),
            $(go.Panel,  this.panelShapePortStyle(),
                $(go.Panel, { type: go.Panel.Table},
                    $(go.Shape, this.shapeGeometryStyle()),
                    $(go.Shape, this.innerShapeGeometryStyle()),
                ),
                new go.Binding('itemArray', 'ports'),
                {
                    itemTemplate: $(go.Panel, this.portPanelStyle(),
                        $(go.Shape, this.portStyle())
                    )
                },

            ),
            $(go.TextBlock, this.textBlockStyle()),
        ),
    );

NodeStyle

private nodeStyle(configurationService: ModelEditorConfiguratorService) {
    const thisGraph = this;
    return [
        {
            type: go.Panel.Spot,
            selectionAdorned: false,
            shadowOffset: new go.Point(0, 0),
            shadowBlur: 15,
            shadowColor: 'blue',
            resizable: true,
            resizeObjectName: 'NODESHAPE',
            locationObjectName: 'NODESHAPE',
            selectionObjectName: 'NODESHAPE',
            locationSpot: go.Spot.Center,
            cursor: 'move',
            mouseEnter: function (e, node) {
                thisGraph.mouseNode(e, node, true)
            },
            mouseLeave: function (e, node) {
                thisGraph.mouseNode(e, node, false)
            },
            doubleClick: function (e, obj ) {    // double click to get action.  using double becuase single click is select
                configurationService.shapeClickAction(obj.data, e)
            },
            contextClick : function (e, obj) {    // rich click to get action
                configurationService.shapeContextClickAction(obj.data)
            },

        },
        new go.Binding('location', 'location', go.Point.parse).makeTwoWay(go.Point.stringify),
        new go.Binding('isShadowed', 'isSelected').ofObject()
    ];
}

CommonShape

private shapeGeometryStyle() {
    return [
        { isPanelMain: true },
        {
            name: 'NODESHAPE',
            fill: 'white',
            stroke: 'black',
            strokeWidth: 0.80,
            strokeCap: 'round',
            strokeJoin: 'round',
            strokeDashArray: null,
            // row: 0, column: 0,
            geometryStretch: go.GraphObject.Uniform,
            // isPanelMain: true
        },
        new go.Binding('fill', '', this.getShapeFill),
        new go.Binding('geometryString', 'figure'),
        new go.Binding('width', 'width').makeTwoWay(),
        new go.Binding('height', 'height').makeTwoWay(),
        new go.Binding('stroke', 'lineColor'),
        new go.Binding('strokeWidth', 'lineWidth'),
        new go.Binding('strokeDashArray', 'linePattern', this.getLinePattern)
    ];
}

InnerShape

private innerShapeGeometryStyle() {
    return [
        {
            name: 'NODESHAPE',
            fill: 'transparent',
            stroke: 'transparent',
            strokeWidth: 0.80,
            strokeCap: 'round',
            strokeJoin: 'round',
            strokeDashArray: null,
            geometryStretch: go.GraphObject.Uniform,
            // row: 0, column: 0,
            scale: 1
        },
        // new go.Binding('alignment', 'offset',go.Spot.parse),
        new go.Binding('fill', 'innerColor'),
        new go.Binding('geometryString', 'innerFigure'),
        new go.Binding('width', 'width').makeTwoWay(),
        new go.Binding('height', 'height').makeTwoWay(),
        new go.Binding('stroke', 'innerStrokeColor'),
        new go.Binding('scale', 'innerScale')

    ];
}

The figure is show correctly but the panel table creates the border in all the node, and is only needed in the figure:
This is the wrong behavior

This is what should work:

Hope all the info helps.

Thank you.

I’m not sure what your question is, but I’ll guess that you want to give the outer nested Panel a name and use that name as the value of Node.resizeObjectName.

Please read GoJS Tools -- Northwoods Software.

I need the shape to be resized not the panel. The Node.resizeObjectName is set to “NODESHAPE”

Oh, OK. But now I notice that you have multiple objects with that same name. That’s probably a bad idea.

So maybe you want to name and have as the resizeObject the inner panel, the Table Panel. And either set Panel.defaultStretch to go.GraphObject.Fill on that panel or set GraphObject.stretch to go.GraphObject.Fill on each of its two Shapes. That will cause each Shape to fill the area occupied by the single cell of that Table Panel, since you haven’t set row or column on either Shape.

By the way, the default scale is 1 and the default strokeDashArray is null, so you don’t have to set those properties. Or stroke to “black”.

Ok, I set different names for the diffrents objects, the inner panel I put in the Node.resizeObjectName and tried setting the inner panel defaultStrech to fill, or setting the two shapes with fill (tried to with geometryStrech because my shapes are geometryString) and the shapes are not resizing when the panel resize.

Did you set the stretch (or Panel.defaultStretch) to make the elements of the Panel stretch to fill the available space?

Shape.geometryStretch only controls how the geometry adjusts to the size of the Shape.

https://gojs.net/latest/intro/sizing.html#StretchingOfGraphObjects

II tried the two ways:

Panel.defaultStretch: go.GraphObject.Fill (in the inner Table Panel)

and tried to:

stretch: go.GraphObject.Fill (in both shapes)

Still not working.

It seems that the problem is setting the height and width in the shapes. If I remove the binding in the shape this are stretching but the panel still is not sorrounding the shape: I corrected it setting the geometryStretch to fill

I also need that width and height how to set it with the strectching too. Setting the minSize, I have to set the binding with makeToWay()

Thanks

That should work. Here’s my attempt, minus the ports that you have:

    myDiagram.nodeTemplate =
      $(go.Node, "Vertical",
        { resizable: true, resizeObjectName: "SHAPES" },
        $(go.Panel, "Table",
          { name: "SHAPES", defaultStretch: go.GraphObject.Fill },
          new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
          $(go.Shape, { fill: "white" },
            new go.Binding("fill", "color"),
            new go.Binding("figure")),
          $(go.Shape, { fill: "red", margin: 10 },
            new go.Binding("figure", "figure2"))
        ),
        $(go.TextBlock, { margin: 8 },
          new go.Binding("text"))
      );
    myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Alpha", color: "lightblue", figure: "TriangleUp", figure2: "SevenPointedStar" }
    ]);

Here’s the result on the left, along with a resized copy of the node on the right:

Now is working, but I need the Uniform of the geometry. The shapes must be consistent with the ports:

Correct resizing:

What is happening now with geometryStrech to Uniform

Ah, well, that’s why I originally suggested resizing the panel holding the ports as well as the (panel of) shapes.

How can achieve that? Can be in resizableObjectName several objects?

Maybe is there a better way, what exactly need is the two shapes (one overlaps the other when is defined), sometimes the innerShape is not defined so needs to be transparent (not be visible), maybe another type of panel (not table) or removing the panel?

    myDiagram.nodeTemplate =
      $(go.Node, "Vertical",
        { selectionObjectName: "BODY" },
        { resizable: true, resizeObjectName: "BODY" },
        $(go.Panel, "Spot",
          { name: "BODY" },
          new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
          $(go.Panel, "Table",
            { margin: 6, defaultStretch: go.GraphObject.Fill },
            $(go.Shape, { fill: "white" },
              new go.Binding("fill", "color"),
              new go.Binding("figure")),
            $(go.Shape, { fill: "red", margin: 10 },
              new go.Binding("figure", "figure2"))
          ),
          $(go.Shape, "XLine", { width: 10, height: 10, alignment: new go.Spot(0.3, 1) }),
          $(go.Shape, "XLine", { width: 10, height: 10, alignment: new go.Spot(0.7, 1) })
        ),
        $(go.TextBlock, { margin: 8 },
          new go.Binding("text"))
      );

Note how the resizeObjectName now names the Spot Panel, and that I moved the Binding of desiredSize up to that Panel.

I also added a margin to the Table Panel, so that there is room for the two “ports” beyond the bottom of the Table Panel.

Still not working, here is my complete template:

private createNodeTemplateMap(): go.Map<string, go.Node> {
    const templateMap = new go.Map<string, go.Node>('string', go.Node);

    templateMap.add('geometryWithLabel',
        $(go.Node, this.nodeStyle(this.configuratorService),
            $(go.Panel,  this.panelShapePortStyle(),
                $(go.Panel, this.innerPanelShapeStyle(),
                    $(go.Shape, this.shapeGeometryStyle()),
                    $(go.Shape, this.innerShapeGeometryStyle()),
                ),
                new go.Binding('itemArray', 'ports'),
                {
                    itemTemplate: $(go.Panel, this.portPanelStyle(),
                        $(go.Shape, this.portStyle())
                    )
                },

            ),
            $(go.TextBlock, this.textBlockStyle()),
        ),
    );

private nodeStyle(configurationService: ModelEditorConfiguratorService) {
    const thisGraph = this;
    return [
        {
            type: go.Panel.Spot,
            selectionAdorned: false,
            shadowOffset: new go.Point(0, 0),
            shadowBlur: 15,
            shadowColor: 'blue',
            resizable: true,
            resizeObjectName: 'NODEPANEL',
            locationObjectName: 'NODEPANEL',
            selectionObjectName: 'NODEPANEL',
            locationSpot: go.Spot.Center,
            cursor: 'move',
            mouseEnter: function (e, node) {
                thisGraph.mouseNode(e, node, true)
            },
            mouseLeave: function (e, node) {
                thisGraph.mouseNode(e, node, false)
            },
            doubleClick: function (e, obj ) {    // double click to get action.  using double becuase single click is select
                configurationService.shapeClickAction(obj.data, e)
            },
            contextClick : function (e, obj) {    // rich click to get action
                configurationService.shapeContextClickAction(obj.data)
            },

        },
        new go.Binding('location', 'location', go.Point.parse).makeTwoWay(go.Point.stringify),
        new go.Binding('isShadowed', 'isSelected').ofObject()
    ];
}

private panelShapePortStyle() {
    return [
        {
            type: go.Panel.Spot,
            name: 'NODEPANEL',
            defaultStretch: go.GraphObject.Fill,
            // defaultGeometryStretch: go.GraphObject.Fill,
        },
        new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
    ];
}

private innerPanelShapeStyle() {
    return [
        {
            type: go.Panel.Table,
            name: 'INNER_NODEPANEL',
            stretch: go.GraphObject.Fill,
            // defaultStretch: go.GraphObject.Fill,
            // defaultGeometryStretch: go.GraphObject.Fill,
        }
    ];
}

private shapeGeometryStyle() {
    return [
        {
            name: 'NODESHAPE',
            fill: 'white',
            stroke: 'black',
            strokeWidth: 0.80,
            strokeCap: 'round',
            strokeJoin: 'round',
            strokeDashArray: null,
            // row: 0, column: 0,
            stretch: go.GraphObject.Fill,
            geometryStretch: go.GraphObject.Uniform,
        },
        new go.Binding('fill', '', this.getShapeFill),
        new go.Binding('geometryString', 'figure'),
        new go.Binding('width', 'width').makeTwoWay(),
        new go.Binding('height', 'height').makeTwoWay(),
        new go.Binding('stroke', 'lineColor'),
        new go.Binding('strokeWidth', 'lineWidth'),
        new go.Binding('strokeDashArray', 'linePattern', this.getLinePattern)
    ];
}

private innerShapeGeometryStyle() {
    return [
        {
            name: 'INNER_NODESHAPE',
            fill: 'transparent',
            stroke: 'transparent',
            strokeWidth: 0.80,
            strokeCap: 'round',
            strokeJoin: 'round',
            strokeDashArray: null,
            // row: 0, column: 0,
            stretch: go.GraphObject.Fill,
            geometryStretch: go.GraphObject.Uniform,
        },
        new go.Binding('fill', 'innerColor'),
        new go.Binding('geometryString', 'innerFigure'),
        // new go.Binding('width', 'width').makeTwoWay(),
        // new go.Binding('height', 'height').makeTwoWay(),
        new go.Binding('stroke', 'innerStrokeColor'),
        new go.Binding('scale', 'innerScale')

    ];
}

private portPanelStyle() {
    return [
        {
            type: go.Panel.Spot
        },
        new go.Binding('portId', 'name'),
        new go.Binding('fromSpot', 'fromSpot', go.Spot.parse),
        new go.Binding('toSpot', 'toSpot', go.Spot.parse),
        new go.Binding('alignment', 'alignment', go.Spot.parse),
        new go.Binding('fromLinkable', '', ((port: Port) => {
            switch (port.type) {
                case PortType.Input:
                    return false;
                case PortType.Output:
                case PortType.InputOutput:
                    return true;
            }
        })),
        new go.Binding('fromMaxLinks', '', ((port: Port) => {
            switch (port.type) {
                case PortType.Input:
                    return 0;
                case PortType.Output:
                case PortType.InputOutput:
                    return 1;
            }
        })),
        new go.Binding('toLinkable', '', ((port: Port) => {
            switch (port.type) {
                case PortType.Output:
                    return false;
                case PortType.Input:
                case PortType.InputOutput:
                    return true;
            }
        })),
        new go.Binding('toMaxLinks', '', ((port: Port) => {
            switch (port.type) {
                case PortType.Output:
                    return 0;
                case PortType.Input:
                case PortType.InputOutput:
                    return 1;
            }
        }))
    ];
}

private portStyle() {
    return [
        {
            name: 'PORT',
            figure: 'XLine',
            width: 10,
            height: 10,
            background: 'transparent',
            fill: null,
            stroke: null,
            angle: 90,
            cursor: 'pointer',
            toolTip: portToolTip
        }
    ];
}

This is the behavior right now

And it shoul be

I don’t know what to say. How is your node template design fundamentally different from what I posted, ignoring a variable number of ports?

That is my question. I have the same desing of the Node and the behavior of the resized of the panel is wrong. I just want two shapes, ones overlaps the other (sometimes is transparent). If a put in them in the Panel.Table the resized is weird.

Thanks

It seems that the problem is the geometryStretch: go.GraphObject.Uniform, in the shapes. We need the geometryStretch: go.GraphObject.Uniform in the shapes but the selection/resize box should maintain the size of the shapes too.

I just tried adding geometryStretch: go.GraphObject.Uniform to both of the Shapes in the template that I gave you above. Is your complaint that when the panel is given a size that has a different aspect ratio than its shapes, the ports no longer line up with the features of the shape(s)?

If that’s the case, one possibility is to use a Viewbox Panel:

    myDiagram.nodeTemplate =
      $(go.Node, "Vertical",
        { selectionObjectName: "BODY" },
        { resizable: true, resizeObjectName: "BODY" },
        $(go.Panel, "Viewbox",
          { viewboxStretch: go.GraphObject.Uniform },
          { name: "BODY" },
          $(go.Panel, "Spot",
            new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
            $(go.Panel, "Table",
              { margin: 6, defaultStretch: go.GraphObject.Fill },
              $(go.Shape, { fill: "white" },
                new go.Binding("fill", "color"),
                new go.Binding("figure")),
              $(go.Shape, { fill: "red", margin: 10 },
                new go.Binding("figure", "figure2"))
            ),
            $(go.Shape, "XLine", { width: 10, height: 10, alignment: new go.Spot(0.3, 1) }),
            $(go.Shape, "XLine", { width: 10, height: 10, alignment: new go.Spot(0.7, 1) })
          )
        ),
        $(go.TextBlock, { margin: 8 },
          new go.Binding("text"))
      );

Note that the user now resizes the Viewbox Panel, no longer the Panel holding the ports.

I tried with the viewbox but its “zooms” to the figures inside so the width of the strokes and the ports is getting big as the panel goes big.

I found out now without the viewbox and setting the Node resizedObject to the Panel that holds the two shapes that is getting closed of what we need. The only problems is the uniform in the resized that we used to have unitl we add the second shape (with the panel).

This is what we used to have (with one Shape, one geometry

):

In this case the widht and height are uniform and always the shape is a square.

When I add the seconde shape (second geometry), the resize is not uniform anymore:

Is there a way to maintain the resize uniform like a square (adding a shape transparent like a square with the same width and height of the shapes (geometries) maybe? because with the panels I cannot find a way to solve this) mantaing the ports around the shape (and the selection box).

Thanks.

I don’t understand what you are doing. Could you modify the template that I provided and show us? It is a lot simpler than what you have, so it’s easier for us to understand and modify.