Tooltip disappearing and appearing when moving inside the Node

Hi there,
I have been working with the GoJs library for the last few weeks and managed to solve most problems I encountered. Today though I have a problem with the ToolTip for my nodes. Basically when i hover with the mouse above the node, the tooltip will show, but if I then go and move around more inside the same node the tooltip keeps disappearing and appearing again. It will do this whenever you enter or leave one of the textblocks or images inside of the node.

This is very annoying when you try to click the buttons inside the tooltip as it will disappear when you start moving the mouse pointer.

I searched for some solutions and found that setting the background property of the adornment to “transparent” should resolve this problem. Sadly it still causes problems for me.

organisationDiagram.nodeTemplate.toolTip=tooltip;
var tooltip= $(go.Adornment, "Auto", { background: "transparent" }, // avoid hiding tooltip when mouse moves $(go.Shape, "Rectangle", { fill: "white", stroke: "black" }), new go.Binding("visible","",function(node){initialiseTooltip(node);return true;}), $(go.Panel,"Table", { margin: 3, alignment:go.Spot.TopLeft } ) );

Hope you can help! Sorry for poor formatting, never asked for help in forums before

You should be able to indent the code that you quoted.

I suspect you also need to set the Node.background to be “transparent”.

Thanks for your answer!
I tried but sadly it didn’t help. Now I am trying another approach which I think should be easier.
Is there a way to change the hideToolTip() method of the ToolManagerClass, making it so that the currently opened tooltip will only disappear if the mouse pointer leaves the tooltip or the element to which it is attributed?

I’m not too sure what you want to do exactly, but you can customize the hideToolTip code. It may lead to unintended issues if you’re not careful, though.

myDiagram.toolManager.hideToolTip = function() {
  // do some custom code, maybe return to stop the tool tip from hiding

  // if you don't return, call the base functionality:
  go.ToolManager.prototype.hideToolTip.call(this);
};

Depending on what you want to do, perhaps it would be better to set the toolTipDuration to something very large, such as 20 seconds, and then have your own code call hideToolTip when you want to, instead of trying to customize hideToolTip.

I solved the problem in the end by changing the tooltip to only appear on hover of a specific part inside the node, instead of the whole node.
I have another question regarding the tooltip. The tooltip that I create changes in size based on what node I am currently hovering on. This causes the tooltip to sometimes go offscreen (i.e. doesn’t fit inside the diagram div). Is it possible to automatically position the tooltip such that it will always be placed in a way that it fits?

I have tried using the alignment and alignmentFocus parameter, but it seems odd that I have to set them specifically for every instance where the tooltip might go offscreen.

Thanks a lot!

If your tooltip Adornment uses a Placeholder, the Placeholder is always positioned wherever the Adornment.adornedObject is.

But you appear not to be using a Placeholder in the Adornment that you posted originally in this forum topic, so the default behavior of ToolManager.positionToolTip is described at ToolManager | GoJS API.

If you don’t like that behavior, you could override the method to do whatever you like.

I had to change the previous toolTip, it now looks like this and I add elements to the Table Panel depending on the node (this is done in the visibility binding as I could find no other way to add panel components dynamically).

     toolTip:
         $(go.Adornment, "Spot",
             {background: "transparent" },
             $(go.Placeholder, { padding: 5 }),
             $(go.Panel,"Table",
                 { 
                     name: "toolTipTable",
                     margin: 3,
                     background:"white"
                  },
              new go.Binding("visible","",function(node){initialiseTooltip(node);return true})
           )
      )

Adornments are data bound to the same data as the adorned GraphObject. If you have an Array of items in the data, you can bind some Panel.itemArray to that, just as you can within regular Nodes or Links.
http://gojs.net/latest/intro/itemArrays.html

The problem is that I don’t have the data for those panels saved in the node data as seen in the example. My node data for this tooltip are Departments inside a company and when I build the tooltip I scan through another array containing data of staff members. If they belong to the department (they have a department_ID attribute) I will add their image and name to the tooltip:

            //creates a list with images and names of the people working inside this organisational unit
            var membersList=[];
            var imageList=[];
            for(var i=0;i<peopleDataArr.length;i++){
               if(""+peopleDataArr[i].organisation_Unit==node.key){
                    membersList.push(peopleDataArr[i].first_Name +" "+ peopleDataArr[i].last_Name);
                    imageList.push(peopleDataArr[i].source);
               }
            }
            //here the tooltip is rebuild, passing the array with images and names of the people in this organisational unit
            for(var i=0;i<membersList.length;i++){
               toolTipTable.add(makeNewTooltipTable(i,membersList[i],imageList[i]));
            }

function makeNewTooltipTable(r,text,link){
//the new part is a small table which will be added to the main and permanent table of the tooltip
//it contains the image of the person and the name. The defaulProfilePicture is used as background.

//allows to view a maximum of 20 people per column
var column=Math.floor(r/20);
r%=20;

var newPart=
$(go.Panel,"Table",
      { 
          isActionable: true ,// handle mouse events without involving other tools
          mouseEnter:function(e,obj,next){obj.background=corpYellow},
          mouseLeave:function(e,obj,next){obj.background="white"},
          click:function(e,obj){getAndDisplayPath(findNodeByPersonName(obj.elt(2).text))},
          background:"transparent",
          row:r,column:column,
          margin: 1,
          alignment:go.Spot.TopLeft
          
      },
          //default picture for person
          $(go.Picture, "Images/defaultProfilePicture.jpg",
            {
                row:0,column:0,
                margin: 4, 
                width: 20, height: 20,
                alignment:go.Spot.TopLeft
            }
          ),
          //real picture of person
          $(go.Picture,
            {
                row:0,column:0,
                margin:4,
                width: 20, height: 20, 
                source:link,
                alignment:go.Spot.TopLeft
            }
          ),
          //name of person
          $(go.TextBlock, 
            {
                row:0,column:1,
                font: '500 12px Roboto, trade-gothic',
                stroke:"black",
                width:100,
                text:text,
                alignment:go.Spot.LeftCenter
            }
          )
     );
return newPart;

}

Can’t really seam to get the formatting right, hope it’s not too ugly to look at

That’s OK – the Array can be generated dynamically.

Say you want to show the names of some or all of the “children” nodes. Define a function that given a Node returns the appropriate Array:

    function findChildrenNames(node) {
      var arr = [];
      node.findNodesOutOf().each(function(n) {
        if (...n...) arr.push(n.data.name);
      });
      return arr;
    }

Then your node template could be like:

    myDiagram.nodeTemplate =
  $(go.Node,
    . . .,
    {
      toolTip:
        $(go.Adornment, "Auto",
          new go.Binding("visible", "", function(ad) { return findChildrenNames(ad.adornedPart).length > 0; }).ofObject(),
          $(go.Shape, { fill: "lightyellow" }),
          $(go.Panel, "Vertical",
            {
              margin: 3,
              itemTemplate: $(go.Panel, $(go.TextBlock, new go.Binding("text", "")))
            },
            new go.Binding("itemArray", "", function(ad) { return findChildrenNames(ad.adornedPart); }).ofObject()
          )
        )
    }
  );

Ok thank you very much. I will try to implement this solution and come back to you when I am done.

Alright I implemented the Array method and the tooltip shows up nicely and I don’t have to worry about the positioning anymore.
Sadly its not all moonlight and roses.

As you can see when I put the pointer above the simble the toolTip correctly shows (obscured data with the black rectangles with white filling).
The problem is when I try to move with the pointer inside of the tooltip (as every person is clickable), as soon as the pointer leaves the border of the yellow image, the toolTip disappears, thus making me unable to reach it.

Any ideas on how to change that?

If you define your tooltip Adornment to use a Placeholder, you can make sure that the Adornment.background is set to “transparent” – not left at the default value of null. That way when the mouse moves away from the original object with that tooltip, it will stay within the tooltip as it moves towards your table/list.

I have tried adding a placeholder to the tooltip in the positions where you can see //Position1 //Position2.

             toolTip:
                 $(go.Adornment, "Auto", {background:"transparent"},
                   new go.Binding("visible", "", function(ad) { return findCollaborators(ad.adornedPart.data).length > 0; }).ofObject(),

                   //Position 1
                   $(go.Shape, { fill: "white",stroke:"black" }),
                   //Position 2
                   $(go.Panel, "Vertical",
                     {
                         margin: 3,
                         itemTemplate: getItemTemplate()
                     },
                     new go.Binding("itemArray", "", function(ad) { return findCollaborators(ad.adornedPart.data); }).ofObject()
                   )
                 )//end adornment

And got the following results:

Position1: The Placeholder seems to form a box around the symbol witht the tooltip and only a tiny part can be displayed inside of it.

Position2: The Tooltip spawns directly onto the mouse pointer, instead of appearing to the side like it used to do. It also doesn’t take borders into account anymore, going off the diagram like in this case on the right side.

Ah, I suggest you learn about using Panels:

      toolTip:
        $(go.Adornment, "Spot",
          { background: "transparent" },
          $(go.Placeholder),
          $(go.Panel, "Auto",
            { alignment: new go.Spot(1, 0.5, 20, 0), alignmentFocus: go.Spot.Left },
            $(go.Shape, { fill: "white" }),
            $(go.Panel, "Vertical",
              { margin: 3, itemTemplate: getItemTemplate() },
              new go.Binding("itemArray", . . .)
            )
          )
        )

Of course you’ll want to fiddle with the alignment and alignmentFocus values so that you have it positioned the way you want relative to your node’s symbol object.

I had tried this option already. But by setting the Adorment to “Spot”, inevitably in some cases the tooltip is going to get cut off by the diagram’s border. The behaviour I would like to have is simply reducable to these 2 points:

  1. Being able to reach the tooltip with the mouse pointer without it disappearing (which thanks to you I managed to do)

  2. Avoid the tooltip from disappearing outside of the diagram’s boundaries.

As of now I am able to achieve those two things separately. I am unable to combine them and to obtain a final result with both features. I feel like achieving Point 1, forces me to use a placeholder and a “Spot” Adornment, but those are not compatible with the automatic allocation of the node in Point 2.

Is it possible to combine these two things or would I need to make Bindings to the alignment focus…?

Thanks for your help, really appreciating the fast answers.

To make sure the Adornment(s) stay within the diagram’s bounds, i.e. Diagram.documentBounds, you could increase the Diagram.padding so that there is always room on the side where you position the adornment.

I think this would only work as temporary solution, as I can never know how far the tooltip will actually go out of the border. So setting a padding would merely save me some cases where the tooltip would only go out by a few pixels.

I settled with using a Placeholder so at least the tooltip will be clickable, in some cases the tooltip will go out of the borders but I am just going to accept that and focus on other parts of the diagram.

Thanks a lot for your help!

By using the below code the Adornment appears on top of the shape.
But in my case, i should be able to do other operations,
like: editing text, or connecting new node,
But since on hover the shape gets covered with tooltip I’m not able to do anything.
Only reason to use Adornment is solve the tooltip hide issue, (on moving the mouse inside the shape tooltip gets hidden automatically)

Do we have any solution so that we can operate other things while tooltip is there?

toolTip: $(go.Adornment, "Spot",
      { background: "red", margin: 10, opacity: 0.5, },
      $(go.Placeholder),
      $(go.Panel, "Auto",
        { alignment: new go.Spot(1, 0.5, 20, 0), alignmentFocus: go.Spot.Left },
        $(go.Shape, {
          fill: "#FCF3D3",
          stroke: "#FCF3D3",
        }),
        $(go.Panel, "Vertical",
          { margin: 3, },
          $(
            go.TextBlock,
            {
              font: "400 14px sans-serif",
              margin: 10,
              text: "Activity cannot have more than 2 incoming",
            },
          )
        )
      )
    )

image

Create a new named Layer that is Layer.isTemporary and that is before/behind the “Background” layer by calling Diagram.addLayerBefore. Set Adornment.layerName to the name of your new Layer.