Displaying a button on a node on hover


Is there a way I can display a button in a node only when I hover over it?

Thanks in advance.

Sure, that’s easy. Here’s the minimal.html sample modified to show two buttons for a node when the user hovers over it for 400 milliseconds: http://gojs.net/latest/samples/hoverButtons.html.

Interesting - the example runs right when I run it from your url, but copying the file to my setup causes problems:

  1. When I copy the source to a local file (and replace the url for go.js with my local copy “http://localhost/assets/gojs.js?id=123”) and try running it (via a file://) I get this error: Error: Trying to set undefined property “hoverDelay” on object: Diagram “myDiagram”. The diagram does not render. Am I using a different version of go.js than I ought to?

  2. Commenting the hoverDelay line in the example causes the diagram to render; however the buttons appear clumped together on the top left side of the node I hovered on, while in your example, they appear on either side of the node. What could be causing this discrepancy?

  3. In my case - when the hover buttons are clumped together - leaving the node without touching the buttons does not cause the buttons to disappear. The buttons only disappear after I run the mouse over them, and then away - probably because your mouseLeave event is only triggered when I leave the adornment?

  4. Furthermore, hovering over a different node afterwards causes the buttons to appear in the same place they appeared before, in the top left corner of the first node i hovered over. What could be causing this?

Maybe you are using an old version of go.js? The first text line of go.js should tell you the version number.

BTW, we will be releasing the final (?) beta of version 1.2 today.

I believe we are using 1.1.11.

Should I be getting 1.2beta3?

Yes, you should start using 1.2 beta, which is now 1.2 beta 4.

Thanks! Switching to 1.2beta4 helps.

This is going into a production environment - are there any known issues with this release?

Also, while the click event seems to work for the button in the adornment, it does not seem to be triggered for a picture, built like so:

                    width: theme.toolbarIconWidth,
                    height: theme.toolbarIconHeight,
                    imageStretch: go.GraphObject.Fill,
                    source: theme.profileDetailsIconURL,
                    margin: 2,
                    click: function (e, obj) {
                        controller.showDetails(e, obj.part.adornedPart);
                        $(go.Adornment, go.Panel.Auto,
                            $(go.Shape, { fill: theme.toolTipBackgroundColor }),
                            $(go.TextBlock, { margin: theme.toolTipMargin },
                                $i18n($i18n.CONTENT, 'kI18nOrgChartDetailsTip')

The click event is triggered when the picture is a part of my node template. Additionally, the same method gets triggered just fine when bound to the click event of the button.

Am I missing something?

Well, we just put out this version, so of course we do not know of any significant problems. You will have to do your own testing to decide if it satisifies your requirements for distributing with your app.

Are you putting this Picture into the Button? Then it would make sense that any click event handler would not be called, because the Button intercepts the InputEvents, preventing your Picture from getting them. The idea is that it would be very confusing to the user if different areas inside a Button behaved differently, not like a “button”.

Nope, we tried using the picture standalone. We’ve made do by embedding the picture into a button, and defining a click method for that button.

Warning: wall of code incoming :)

I notice that once the adornment appears, clicking on the node itself does not cause the node to be selected. I modified your example to try to add a click event (pasted below) to the adornment; clicking either button triggers the click event of the adornment, but clicking the node itself (the area between the buttons) does not trigger the click event. I need to be able to select the node by clicking it, even after the mouseHover event has been triggered. Is there a way I can accomplish this?

<!doctype html>

Minimal GoJS Sample

Minimal GoJS Sample

This isn't a truly minimal demonstration of GoJS, because we do specify a custom Node template, but it's pretty simple. Click on the link below to see source code for this page, or use your browser's "View Page Source" command.

The Node template data-binds both the text string and the shape's fill color.

You can select, move, copy, delete, and undo/redo.

The Diagram.initialContentAlignment setting causes the diagram's contents to appear in the center of the diagram's viewport.

On touch devices, hold your finger stationary to bring up a context menu. The default context menu supports most of the standard commands that are enabled at that time for that object.

For a more elaborate and capable sample, see the Basic sample.

Thanks in advance.

OK, there are two issues. One is that because the Adornment is a temporary Part (i.e. in a Layer that is Layer.isTemporary), you need to set isActionable to true. You’ll notice that Buttons are defined in this manner.

The other issue is that there is a bug in ActionTool.canStart so that it didn’t work when you set Part.isActionable to true. We have fixed that for version 1.2. In the meantime, you can just define your click handler and set .isActionable on the Placeholder. That also means setting its background to non-null, so that it can receive mouse events.

I have updated that hoverButtons.html sample. Here’s the updated code:

[code] var nodeHoverAdornment =
(go.Adornment, "Spot", { background: "transparent", mouseLeave: function(e, obj) { var ad = obj.part; ad.adornedPart.removeAdornment("mouseHover"); } }, (go.Placeholder,
background: “transparent”, // to allow this Placeholder to be “seen” by mouse events
isActionable: true, // needed because this is in a temporary Layer
click: function(e, obj) {
alert(“clicked Placeholder”);
var node = obj.part.adornedPart;
("Button", { alignment: go.Spot.Left, alignmentFocus: go.Spot.Right }, { click: function(e, obj) { alert("Hi!"); } }, (go.TextBlock, “Hi!”)),
("Button", { alignment: go.Spot.Right, alignmentFocus: go.Spot.Left }, { click: function(e, obj) { alert("Bye"); } }, (go.TextBlock, “Bye”))

// define a simple Node template
myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape, "RoundedRectangle",
      // Shape.fill is bound to Node.data.color
      new go.Binding("fill", "color")),
      { margin: 3 },  // some room around the text
      // TextBlock.text is bound to Node.data.key
      new go.Binding("text", "key")),
      mouseHover: function(e, obj) {
        var node = obj.part;
        nodeHoverAdornment.adornedObject = node;
        node.addAdornment("mouseHover", nodeHoverAdornment);

Thanks - that works for me.

Hi Walter,

As a followup, the addition of a hover adornment to a node causes the hover event defined for various TextBlocks within the node to cease being triggered. Is there something I can do to get that working?

That is because mouse events are being handled by the node’s adornment, so they are not reaching any of the GraphObjects in the Node.

Maybe you do not want to use an Adornment when hovering at all. Instead, hovering should add some buttons to the Node itself. That would also avoid the issue with clicking on the node not selecting it, which we worked around by complicating the Adornment, in red code in my earlier reply.

Thanks, Walter. I’ll probably need to set the buttons into the node itself.