Make label on the link be either vertical or horizontal only

Hi,

I’m trying to figure out whether it is possible to position label on the link either horizontally or vertically.

I’m trying to avoid following situation.

My label is inside go.Panel with the following properties:

            $GO(go.Panel,
                "Auto",
                {
                    cursor: "pointer",
                    alignment: go.Spot.Center,
                    alignmentFocus: go.Spot.Center,
                    segmentFraction: 0.5,
                    segmentOrientation: go.Orientation.Upright,
                },

That’s unusual. I remember someone recently asking for exactly that kind of behavior, but I guess that wasn’t you? How have you defined your link template and your Link subclass?

It wasn’t me.

I use default go.Link with the following settings.

            zOrder: -5,
            selectionAdorned: true,
            adjusting: go.LinkAdjusting.None,
            toEndSegmentLength: 25,
            fromEndSegmentLength: 25,
            toShortLength: 5,
            fromShortLength: 0,
            relinkableFrom: true,
            relinkableTo: true,
            reshapable: true,
            resegmentable: true,
            shadowOffset: new go.Point(2, 2),
            shadowBlur: 10,
            selectionAdornmentTemplate: !interactive ? null : selectionTemplate,
            isActionable: interactive,
            routing: go.Routing.AvoidsNodes,
            curve: go.Curve.JumpOver,
            corner: 20,

Ah, that’s because of the large Link.corner value.

Try setting segmentIndex: 2 on your label (the Panel).

BTW, setting alignment there has no effect. And the alignmentFocus defaults to 0.5 for that situation, so I think you don’t need to set that property either.

@walter thanks, this approach works.
However, it creates other problems as the label is often positioned incorrectly.

Is there way to define that label should be positioned on the longest segment, I think it would solve my problem. 🤔

There isn’t such an Orientation choice, but thanks for the suggestion.

What are the current properties on the link label and on the Link?

@walter here is code example

 // Initialize the diagram
    const $ = go.GraphObject.make
    const diagram = $(go.Diagram, diagramRef.current, {
      "undoManager.isEnabled": true,
      model: new go.GraphLinksModel({
        linkKeyProperty: "key",
      }),
      "animationManager.isEnabled": false,
    })

    // Create a selection adornment template for links
    const selectionTemplate = $(
      go.Adornment,
      "Link",
      $(go.Shape, { isPanelMain: true, stroke: "#00A9C9", strokeWidth: 3 }),
      $(go.Shape, { toArrow: "Standard", stroke: null, fill: "#00A9C9" }),
    )

    // Define the node template
    diagram.nodeTemplate = $(
      go.Node,
      "Auto",
      {
        width: 120,
        height: 60,
        selectionAdorned: true,
      },
      $(go.Shape, "RoundedRectangle", {
        fill: "#EFEFEF",
        stroke: "#333333",
        strokeWidth: 1.5,
      }),
      $(
        go.TextBlock,
        {
          margin: 8,
          font: "bold 12px sans-serif",
          stroke: "#333333",
          editable: true,
        },
        new go.Binding("text"),
      ),
    )

    // Define the link template with all the specified settings
    const interactive = true
    diagram.linkTemplate = $(
      go.Link,
      {
        zOrder: -5,
        selectionAdorned: true,
        adjusting: go.LinkAdjusting.None,
        toEndSegmentLength: 25,
        fromEndSegmentLength: 25,
        toShortLength: 5,
        fromShortLength: 0,
        relinkableFrom: true,
        relinkableTo: true,
        reshapable: true,
        resegmentable: true,
        shadowOffset: new go.Point(2, 2),
        shadowBlur: 10,
        selectionAdornmentTemplate: !interactive ? null : selectionTemplate,
        isActionable: interactive,
        routing: go.Routing.AvoidsNodes,
        curve: go.Curve.JumpOver,
        corner: 20,
      },
      $(go.Shape, { strokeWidth: 2, stroke: "#555" }),
      $(go.Shape, { toArrow: "Standard", stroke: null, fill: "#555" }),
      $(
        go.Panel,
        "Auto",
        {
          cursor: "pointer",
          alignment: go.Spot.Center,
          alignmentFocus: go.Spot.Center,
          segmentFraction: 0.5,
          segmentOrientation: go.Orientation.Upright,
          background: "white",
        },
        $(go.Shape, "RoundedRectangle", {
          fill: "#FFFFFF",
          stroke: "#555555",
          strokeWidth: 1,
        }),
        $(
          go.TextBlock,
          {
            font: "10pt sans-serif",
            stroke: "#333333",
            editable: true,
            textAlign: "center",
            wrap: go.TextBlock.WrapFit,
          },
          new go.Binding("text", "text"),
        ),
      ),
    )

    // Create the model data
    const nodeDataArray = [
      { key: 1, text: "Node 1", loc: "100 100" },
      { key: 2, text: "Node 2", loc: "300 100" },
    ]

    const linkDataArray = [
      {
        key: -1,
        from: 1,
        to: 2,
        text: "This is a much longer link text that.",
      },
    ]

    // Initialize the model
    diagram.model = new go.GraphLinksModel({
      nodeDataArray: nodeDataArray,
      linkDataArray: linkDataArray,
      linkKeyProperty: "key",
    })

    // Position nodes
    diagram.nodes.each((node) => {
      const data = node.data
      if (data.loc) {
        const parts = data.loc.split(" ")
        node.location = new go.Point(Number.parseInt(parts[0]), Number.parseInt(parts[1]))
      }
    })

If you set the label’s segmentOrientation to None, the label will always be horizontal (or to whatever angle you have set or bound).

Maybe we can add another Orientation type or segment… parameter in v3.1. We can look into it.

@walter Unfortunately, I cannot make all my links to be horizontal, as we use vertical connections extensively, and labels will overlap nodes around, see the screenshot.

I could change corner to be 10px instead 20px, in this case always label either vertical or horizontal.
However, in this case it looks strange, as the label is aligned along a short segment, in this case I would prefer to keep it horizontal.

Is there way we could control it?

Try this override of Link.computeAngle:

class CustomLink extends go.Link {
  computeAngle(obj, orient, angle) {
    if (orient === go.Orientation.Upright) {
      const p0 = this.getPoint(0);
      const pn = this.getPoint(this.pointsCount-1);
      // assume zero if there's not enough vertical room for the width of the object
      if ((angle === 90 || angle === 270) && Math.abs(pn.y-p0.y) < obj.measuredBounds.width) return 0;
      // make upright
      if (angle > 90 && angle < 270) angle -= 180;
      if (angle < 0) angle += 360;
      return angle;
    } else {
      return super.computeAngle(obj, orient, angle);
    }
  }
}

Or fiddle with that code to suit your circumstances and preferences.

@walter thank you, I will give it a try. 👍

Is computeAngle some internal method?
I cannot find it in gojs.d.ts typings

Yes, it’s there, both undocumented and undeclared.

@walter I’m still trying to adjust label position. Are we able to compute if the label position on the corner and then modify its position to make sure it is positioned on the straight line?

E.g. we in the following case we could reposition “False” label in the following way:

Current:

Desired position:

Or probably there is a way to dynamically calculate line’s segment to position the label on the longest one?

Yes, one could specify the segmentIndex and segmentFraction so as to place the label where you want it. However there are no virtual methods that one can easily override for determining which segment to place the label on.

@walter thank you for quick reply. It seems neither segmentIndex not segmentFraction will resolve my issue.

The last question I have about label position, is it possible to always position it in the beginning 25-30px from the start?

You can use segmentOffset to do that, combined with setting segmentIndex to indicate which segment to put the label on and segmentFraction to indicate how far along the segment the point should be. The x value for segmentOffset will control the distance along the segment from the point computed by segmentIndex and segmentFraction that the label should be. Also you can set alignmentFocus to control which point in the label that should be co-incident with the point computed by those segment… properties. Please read: Link Labels | GoJS

There is also the special case where either or both of the segmentOffset values are NaN, which will use half the width and half the height as the offset, which is useful in making sure the label doesn’t overlap with the node when the segment… properties specify a point near an end of the link route. A typical example is shown in: Entity Relationship Diagram Nodes have Collapsible Lists of Attributes | GoJS Diagramming Library