Arrowhead bug?

i’m seeing strange arrowhead behavior. using segmentOrientation and segmentOffset works correctly sometimes. yet sometimes not:

here is my link template:

$(go.Link, {
	selectable: false,
	curve: go.Link.Bezier
},

$(go.Shape, {
	name: "SHAPE",
	stroke: DISPLAY.linkColor,
	strokeWidth: 1,
}),

$(go.Shape, {
		name: "TOARROW",
		stroke: DISPLAY.highlightColor,
		fill: DISPLAY.highlightColor,
		segmentOffset: new go.Point(-20,0),
		segmentOrientation: go.Link.OrientAlong
	},
	new go.Binding("toArrow", "toEnd")
),

$(go.Shape, {
		name: "FROMARROW",
		stroke: DISPLAY.highlightColor,
		fill: DISPLAY.highlightColor,
		segmentOffset: new go.Point(20,0),
		segmentOrientation: go.Link.OrientAlong,
	},
	new go.Binding("fromArrow", "fromEnd")))

It’s a linear segmentOffset between the two points, so it isn’t supposed to follow any curves.

what about rotation? the arrowhead just plain doesn’t work with curves. it would be nice to see this documented somewhere instead of wild goose chasing trying to fix it.

Don’t set segmentOrientation or segmentOffset on the arrowheads.

Instead, increase the toEndSegmentLength and fromEndSegmentLength to 40 or 50.

Keep the arrowhead as small as you can – that’s easy to do by setting its scale to something less than 1.0.

For Bezier curves the angle of the arrowhead is actually correct at the end points. However larger arrowheads make it look like the angle is wrong.

i’ve tried a combination of all of these things and nothing works quite right. arrowheads are simply being slapped on top of the end of a link with minimal regard to how that link is connecting to the endpoint. might i suggest a more robust solution that considers the arrowhead as part of the link and sets the link connection point to be on the edge of the arrowhead instead? another option would be to fit the arrowhead to the end of the link in a more intuitively expected way.

OK, here’s what I’ve tried to customize the angle of the arrowhead based on a guess of what might be appropriate for a particular combination of EndSegmentLengths for Bezier-curve Link routes, assuming links go basically horizontally from left to right.

  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          initialContentAlignment: go.Spot.Center,
          layout: $(go.TreeLayout, { setsPortSpot: false, setsChildPortSpot: false }),
          "undoManager.isEnabled": true
        });

    myDiagram.nodeTemplate =
      $(go.Node, "Horizontal",
        $(go.Shape, { portId: "in", width: 8, height: 8, fill: "gray", strokeWidth: 0 }),
        $(go.Shape, { width: 40, height: 40, fill: "gold", strokeWidth: 0 }),
        $(go.Shape, { portId: "out", width: 8, height: 8, fill: "gray", strokeWidth: 0 })
      );

    myDiagram.linkTemplate =
      $(go.Link,
        {
          curve: go.Link.Bezier,
          fromPortId: "out",
          fromSpot: go.Spot.Right,
          fromEndSegmentLength: 20,
          toPortId: "in",
          toSpot: go.Spot.Left,
          toEndSegmentLength: 50
        },
        $(go.Shape),
        $(go.Shape,
          { toArrow: "OpenTriangle", segmentOrientation: go.Link.None },
          new go.Binding("angle", "points", function(pts) {
            var y0 = pts.first().y;
            var y1 = pts.last().y;
            return Math.sqrt(Math.abs(y1-y0)) * ((y1 > y0) ? 1 : -1);
          }).ofObject())
      );

    myDiagram.model =
      $(go.GraphLinksModel,
        {
          archetypeNodeData: {},
          linkDataArray: [
            { from: 1, to: 2 },
            { from: 1, to: 3 },
            { from: 1, to: 4 },
            { from: 1, to: 5 },
            { from: 1, to: 6 },
            { from: 1, to: 7 },
            { from: 1, to: 8 },
            { from: 1, to: 9 }
          ]
        });
  }

The results:

You can fiddle with the GraphObject.angle calculation for the arrowheads based on your configuration. It should depend on not only the fromEndSegmentLength and toEndSegmentLength but on the size of the arrowhead Shape and the distance and direction between the two ports.

This example calculation, as you can see, only depends on the vertical distance, which means you still get bad results if you move the “to” Node much to the left of the “from” Node.