Display an Adornment on hover

I want to implement two different types of Adornments :

  • Blue Adornment when the block is selected
  • And skyblue when the block is hovered.

The Adornment is slightly bigger than the Block shape. And I want to hide it when the cursor leave the Adornment Rectangle. (not the block area)

The issue is : For some reason The mouseLeave event seems to work only when I move the cursor slowly unless I add background or fill attributes.

Here is what I tried.

I created an Adornment generator method :

const adornmentGenerator = (stroke) =>
  $(
    go.Adornment,
    "Spot",
    {
      name: "MY_ADORNMENT",
      // background: "transparent",
      mouseLeave: function (_e, obj) {
        // Work better with background ?!
        obj.part.adornedPart.removeAdornment("mouseHover");
      }
    },
    $(go.Placeholder, {
      isActionable: true
    }),
    $(
      go.Shape,
      "Rectangle",
      {
        name: "MY_RECTANGLE",
        // Or transparent ? However adding a fill won't show the block cursor
        fill: null,
        stroke,
        strokeWidth: 2,
        stretch: go.GraphObject.None
      }
      /* new go.Binding("stroke", "", (isSelected, obj) => {
      console.log("obj", obj);
      return obj.part.isSelected ? "blue" : "skyblue";
    }).ofObject() */
    )
  );

I have now the two Adornment types with different strokes

const selectionAdornmentTemplate = adornmentGenerator("blue");
const hoverAdornment = adornmentGenerator("skyblue");

In the Block Template I have different events with addAdornment and removeAdornment :

mouseOver: function (_e, activeNode) {
      // Show blue adornment
      if (activeNode.part.isSelected) {
        return;
      }
      // Show skyblue adornment
      hoverAdornment.adornedObject = activeNode;
      activeNode.addAdornment("mouseHover", hoverAdornment);
    },
    click: function (_e, activeNode) {
      if (!activeNode.part.isSelected) {
        // Show skyblue adornment
        // after deselecting the block
        hoverAdornment.adornedObject = activeNode;
        activeNode.addAdornment("mouseHover", hoverAdornment);
      }
    },
    selectionChanged: function (activeNode) {
      activeNode.part.removeAdornment("mouseHover");
    },

Any idea how can I enhance this ? Full example here

I guess I don’t understand what you want to do. Your example seems to work well.

The original problem is that when you set the Shape.fill to null or you don’t set the GraphObject.background on your adornment’s Shape or whole Adornment, there will be very little area where the mouseLeave event handler will be invoked. If there is no “paint” at some point in a GraphObject, there are no InputEvents that will happen at that point. Is there a reason you can’t specify Shape.fill to be “transparent” instead of null?

Does the Hover Buttons sample help at all? Buttons that show on Hover
Maybe not, because of the interaction with isSelected.

Yep and due to that small erea sometimes to adornment is still displayed even when the cursor leave the block.

adornmentHover

The problem with Shape.fill or the GraphObject.background is that :
1- In the exmaple, I don’t see the block cursor pointer.
2- My blocks are much more complicated : Sliders, Knobs, Blocks with buttons and textarea … etc. And I don’t want the Adornment to prevent the interaction.

Yes, you cannot easily have it both ways – letting input events “pass-through” the object and letting input events be handled by the same object. I suppose one could explicitly manipulate events in order to get that behavior, but I don’t think it’s needed.

First, you could add a Diagram.mouseOver event handler that removes all such adornments from nodes. (Or can you have at most one at a time? Either way…) However, I think this code would need to check that the InputEvent.documentPoint isn’t inside an adornment that you want to keep visible (just check Rect.containsPoint on the adornment’s actualBounds), so as to handle “holes” in your adornment, such as null fill and background. And do a Diagram.mouseLeave event handler, although in this case you don’t need to check about maybe wanting to keep an adornment.

Second, you could make your GraphObject.mouseOver event handler do the similar thing – remove the adornment(s) from all other nodes. The same check for maybe keeping an adornment applies.

Third, is there a reason you aren’t using GraphObject.mouseEnter instead of mouseOver? Do you need the frequent calls?