Let shape take up segment length

I’m trying to create a hover area shape for my button on a link. I know I can use isPanelMain for taking up the entire link path, but I want to restrict the hover area to the same segment that my button is on. What’s the best way for making sure the height of my hover area shape is the same as the length of that segment?

My hover areas are outlined here:
image
For the hover area on the false link, I would like it to take up that entire vertical segment.

This might be possible. So on (say) a 5-segment link, you only want to highlight the middle segment, is that right?

Will the button ever be anywhere else but the middle?

Why not implement the hover behavior for the whole link, but immediately hide what you want to show when the mouse (i.e. Diagram.lastInput documentPoint is not where you want it to be?

I would only like to highlight the middle, vertical segment.

The button only shows up on the vertical segments.

I haven’t tried this approach. I’ll look into this.

Ok, here’s a somewhat roundabout way to do it. You can have two link shapes that are both isPanelMain:true, so they both run the length of the path. But with the second one, you set a stroke dash so that only the middle 1/5th (or so) of the link is dashed, therefore only the middle 1/5th has the color. You can then toggle this second Shape’s opacity or color as you like in order to highlight.

Here is an example of structuring a Link in that way. You’ll need to make a custom link so that you can be sure to update the stroke dash array appropriately:

https://codepen.io/simonsarris/pen/qBXqaKx?editors=1010

1 Like

Thanks for your suggestions. I’ll try this as well and report back

The multi colored link approach won’t work for us because the button will not always be in the middle. We’re using segmentFraction for the button location and it varies.

After trying Walter’s suggestion of a “no hover” zone, we had concerns around overlapping areas and areas where the “no hover” zone was near a valid hover zone.

As an ideal solution, I wish I could set the hover area shape isPanelMain to true and then set a segmentIndex value so that it would take the shape of that segment.

If there are no other approaches that could work, then the current approach of having the hover areas in a panel with the button will suffice for the first iteration. However, the issue I’m running into with this approach is that when I click the button inside the hover area, the shape for the hover area seems to take the click event, requiring me to click the button again to get the button’s actual click event. Could you help me out with this issue?

Here’s some code demonstrating what I was suggesting:

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

  myDiagram =
    $(go.Diagram, "myDiagramDiv",
      {
        layout: $(go.ForceDirectedLayout)
      });

  myDiagram.nodeTemplate =
    $(go.Node, "Auto",
      $(go.Shape,
        { fill: "white", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" },
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        { margin: 8 },
        new go.Binding("text"))
    );

  myDiagram.linkTemplate =
    $(go.Link,
      {
        routing: go.Link.Orthogonal, corner: 10,
        relinkableFrom: true, relinkableTo: true,
        mouseHover: (e, link) => {
          const idx = link.findClosestSegment(e.diagram.lastInput.documentPoint);
          if (idx === 2) {
            console.log("hovered over " + link.fromNode.key + " --> " + link.toNode.key);
          }
        }
      },
      $(go.Shape, { isPanelMain: true, strokeWidth: 6, stroke: "transparent" }),
      $(go.Shape, { isPanelMain: true }),
      $(go.Shape, { toArrow: "OpenTriangle" }),
      $("Button",
        $(go.TextBlock, "Button"),
        {
          segmentIndex: 2, segmentFraction: 0.5,
          click: (e, button) => console.log("clicked " + button.part.fromNode.key + " --> " + button.part.toNode.key)
        })
    );

  myDiagram.model = new go.GraphLinksModel(
  [
    { key: 1, text: "Alpha", color: "lightblue" },
    { key: 2, text: "Beta", color: "orange" },
    { key: 3, text: "Gamma", color: "lightgreen" },
    { key: 4, text: "Delta", color: "pink" }
  ],
  [
    { from: 1, to: 2 },
    { from: 1, to: 3 },
    { from: 2, to: 2 },
    { from: 3, to: 4 },
    { from: 4, to: 1 }
  ]);
}

The code sample was helpful, thank you.

My choice of words was misleading. I’m using mouseEnter and mouseLeave functions for my “hover” area, not mouseHover. This leads to unexpected behavior depending on where the mouse enters and leaves, e.g. entering from an undesired segment then moving to the desired segment without leaving the “hover” area will not reveal the button.

Would you advise against using mouseOver events? Are there any other ways of knowing if I’m on a different segment?

I’m also still running into an issue where my button (a Picture of an icon) requires a click, hover away, hover over again, then second click to fire its click event. I only run into this issue when I have mouseEnter and mouseLeave modifying the Picture's visible property. Any idea what could be the issue here?

Using GraphObject.mouseOver is needed if you want to change behaviors depending on where the mouse is. I think it’s still convenient to use GraphObject.mouseLeave, though.

  myDiagram.linkTemplate =
    $(go.Link,
      {
        routing: go.Link.Orthogonal, corner: 10,
        relinkableFrom: true, relinkableTo: true,
        reshapable: true, resegmentable: true,
        mouseOver: (e, link) => {
          const button = link.findObject("BUTTON");
          if (!button) return;
          const idx = link.findClosestSegment(e.diagram.lastInput.documentPoint);
          button.visible = idx === 2;
        },
        mouseLeave: (e, link) => {
          const button = link.findObject("BUTTON");
          if (button) button.visible = false;
        }
      },
      $(go.Shape, { isPanelMain: true, strokeWidth: 6, stroke: "transparent" }),
      $(go.Shape, { isPanelMain: true }),
      $(go.Shape, { toArrow: "OpenTriangle" }),
      $("Button",
        $(go.TextBlock, "Button"),
        {
          name: "BUTTON",
          visible: false,
          segmentIndex: 2, segmentFraction: 0.5,
          click: (e, button) => console.log("clicked " + button.part.fromNode.key + " --> " + button.part.toNode.key)
        })
    );