Node shape selection for cornered shape

I have a node that should look like this.

image

the shape is a rectangle the is cut in 2 corners

to implement this I used this code

     go.Shape,
        {
          geometryString: 'FM 8 5 L 9 4 H 17 V 7 L 16 8 L 8 8 V 5 z',
          spot1: new go.Spot(0.08, 0.05),
          spot2: new go.Spot(0.92, 0.95),
          fill: null,
          stroke: 'gray',
        },

when the use select the node I do no want there regular selection adornment,
so I disabled the selectionAdorned

dia.nodeTemplate = $(
      go.Node,
      'Auto',
      {
        selectionAdorned: false,
      },

and on the shape bind the shape stroke based if it is selected like this

 new go.Binding('stroke', 'isSelected', function (s) {
          return s ? 'dodgerblue' : 'black';
        }).ofObject()

so the result looks like this
image

note that Alpha is selected.

I have 2 problems in this solution

  1. the shape of the corners in the solution is changed based on the data inside the node,
    I need it to have the same angle all the time

  2. there is a gap for each item in the Item Array, I need the Item to be stretched to the border of the shape.

here is a link to this sample

Yes, you’ll want to define a custom figure that produces what you want. The main issue is that you’ll want to produce a Geometry that has the angle that you want. The main complication in defining such geometries is dealing with cases when the whole Shape is very small.

You can either adapt one of the figures defined in extensions/Figures.js or extensionsJSM/Figures.ts, or you can wait for me to define such a figure for you, which I can do when I get enough time.

I did produce this figure geometryString: 'FM 8 5 L 9 4 H 17 V 7 L 16 8 L 8 8 V 5 z',

but the problem that it is changing base on the amount of data I have .
the shape can be stretched to all kinds of directions (it can be taller or wider based on the binding)

I need the shape to be constant.
and the data should populate the whole shape.

Yes, the problem is that your Geometry is a particular shape and size. When it’s forced to be a different size based on the contents of the panel, then all it can do is transform proportionally. But that would change the angles of your chamfers. To avoid that you have to define a custom figure by calling the static function Shape.defineFigureGenerator and produce the appropriate Geometry for the Shape’s given width and height. GoJS Shapes -- Northwoods Software

hmmm? can you help me with that?

I have seen the example in the code you sent me,
the problem there is that the text is going out of the shape

I have also the second problem that the content should stretch to the whole shape (it should fill the shape), there should be no white color inside the shape/node

As I said above:

Oh, I might as well ask – did you want whatever is currently in the “Auto” Panel to be clipped by those chamfered corners? That might mean some text or icon could be clipped.

If I understand correctly what you mean, then yes,
all The context should be inside the shape, it should not get out of it.
and also I need the content to be stretched from one side to the other.

maybe I have an idea,
I can use a rectangle shape, and put an icon of triangle in both corners.
the only problem I can think of is how will it behave in case of selection

Here’s the definition of a figure that cuts off 45-degree corners. You can control the length of the side of the triangle, and you can control which corners are cut off.

// parameter1 controls the length of the side of the triangle that is cut off from a corner.
//   The corner is always cut at 45 degrees.  If the width or height is not large enough,
//   the length of the side of the triangle is limited to half of the width or height.
// parameter2 is a bit mask controlling which corners are cut off:
//   1: top-left
//   2: top-right
//   4: bottom-right
//   8: bottom-left
go.Shape.defineFigureGenerator("ChamferedRectangle", (shape, w, h) => {
  let param1 = shape ? shape.parameter1 : NaN;  // how much to cut off from the corner, both X and Y
  if (isNaN(param1)) param1 = 12;
  param1 = Math.min(param1, w / 2);
  param1 = Math.min(param1, h / 2);
  let param2 = shape ? shape.parameter2 : NaN;  // which corners to cut off
  if (isNaN(param2)) param2 = (1 | 2 | 4 | 8);  // default: all corners
  const fig = new go.PathFigure(param1, 0, true);
  const geo = new go.Geometry().add(fig);
  let spot1 = go.Spot.TopLeft.copy();
  let spot2 = go.Spot.BottomRight.copy();
  if (param2 & 2) { // top right
    fig.add(new go.PathSegment(go.PathSegment.Line, w - param1, 0))
       .add(new go.PathSegment(go.PathSegment.Line, w, param1));
    spot1.offsetY = param1/2;
    spot2.offsetX = -param1/2;
  } else {
    fig.add(new go.PathSegment(go.PathSegment.Line, w, 0));
  }
  if (param2 & 4) { // bottom right
    fig.add(new go.PathSegment(go.PathSegment.Line, w, h - param1))
       .add(new go.PathSegment(go.PathSegment.Line, w - param1, h));
    spot2.offsetX = -param1/2;
    spot2.offsetY = -param1/2;
  } else {
    fig.add(new go.PathSegment(go.PathSegment.Line, w, h));
  }
  if (param2 & 8) { // bottom left
    fig.add(new go.PathSegment(go.PathSegment.Line, param1, h))
       .add(new go.PathSegment(go.PathSegment.Line, 0, h - param1));
    spot1.offsetX = param1/2;
    spot2.offsetY = -param1/2;
  } else {
    fig.add(new go.PathSegment(go.PathSegment.Line, 0, h));
  }
  if (param2 & 1) { // top left
    fig.add(new go.PathSegment(go.PathSegment.Line, 0, param1).close());
    spot1.offsetX = param1/2;
    spot1.offsetY = param1/2;
  } else {
    fig.add(new go.PathSegment(go.PathSegment.Line, 0, 0).close());
  }
  geo.spot1 = spot1;
  geo.spot2 = spot2;
  return geo;
});

and the top-left and bottom-right corners of the content of the panel will still stick out, beyond the Shape’s area.

Here’s a possibility for your node template. The header is a separate “Auto” Panel using a “ChamferedRectangle”, and the bottom “Auto” Panel has its own “ChamferedRectangle”, so that each can have its own fill (dark gray for the header and light gray for the list below).

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    { selectionAdorned: false },
    $(go.Shape, "ChamferedRectangle",
      { parameter2: 1|4, spot1: go.Spot.TopLeft, spot2: go.Spot.BottomRight,
        fill: null, strokeWidth: 6 },
      new go.Binding("stroke", "isSelected", s => s ? "red" : "black").ofObject()),
    $(go.Panel, "Vertical",
      { defaultStretch: go.GraphObject.Horizontal },
      $(go.Panel, "Auto",
        $(go.Shape, "ChamferedRectangle",
          { parameter2: 1, fill: "#444", strokeWidth: 0 }),
        $(go.Panel, "Horizontal",
          { alignment: go.Spot.Left },
          $(go.Shape, "Diamond", { width: 16, height: 16, fill: "white" }),
          $(go.TextBlock, { editable: true, stroke: "white" }, "Header")
        )
      ),
      $(go.Panel, "Auto",
        $(go.Shape, "ChamferedRectangle",
          { parameter2: 4, fill: "lightgray", strokeWidth: 0 }),
        $(go.Panel, "Vertical",
          $(go.TextBlock, { editable: true },
            new go.Binding("text").makeTwoWay()),
          $(go.TextBlock, { editable: true }, "FooterFooter")
        )
      )
    )
  );

thanks,
I needed to change SegmentType to PathSegment,

I tried to work with your idea to split the drawing into several shapes,
almost everything is perfect,
the only problem I have is with the shape stroke (when selected and not selected)
the stroke is on all the shape, which make the selection look bad

I need to remove the lines that are marked in red X
image

here is a link to that sample

Maybe you could set the Shape.strokeWidth to zero on those Shapes surrounding your panels, and then surround everything with a “ChamferedRectangle”.

will it not be the problem I started with?

No, because the nested “ChamferedRectangle” Shapes each have their own fill, but now no stroke. I have updated the code above. I also added automatically changing the border to be “red” when the node is selected.

thank you very much, this works, I will try to apply this on my model.
thank you for the help,

I have another problem, I need the strokeWidth of the shape to be wider,
I can not change the shape stroke width because then the all the nodes will be shifted
so I tried to use selectionAdornmentTemplate like this

 go.Node,
      'Auto',
      {
        selectionAdorned: true,
        selectionAdornmentTemplate: new go.Adornment(go.Panel.Auto, {
          isHighlighted: true,
        })
          .add(
            new go.Shape('ChamferedRectangle', {
              parameter2: 1 | 4,
              stroke: 'red',
              strokeWidth: 2,
              fill: null,
            })
          )
          .add(new go.Placeholder()),
      },

the problem now is that II get this gap

image

what can I do to make the stroke to be a little wider?

here is a link to the sample

If you want the non-rectangular border Shape of an “Auto” Panel to fit closer around the contents of that panel, that’s what the Shape.spot1 and spot2 properties control. GoJS Panels -- Northwoods Software