Style hover highlight on context menu

What is the right way to style the background gradient on a context menu when you hover over it?

Right now the default is a white to blue gradient. I am using the example in the “Context Menus” section of the intro page. I am using a ContextMenuButton paradigm instead of the HTML solution. I have tried several ideas. Essentially I created a method (where pfdStyles.contextMenuHoverFillColor holds a valid go.Brush):

function highlightContextMenuItem(event) {

event.targetObject.fill = pfdStyles.contextMenuHoverFillColor;
}

I then have attached this to the mouseOver, mouseHover, even mouseEnter of each ContextMenuButton as shown here:

    GO("ContextMenuButton",{
            "ButtonBorder.fill": pfdStyles.contextMenuColor,
            "ButtonBorder.stroke": pfdStyles.contextMenuStrokeColor,
            click: importDataset,
            mouseOver: highlightContextMenuItem,
            mouseHover: highlightContextMenuItem

},
GO(go.TextBlock,
new go.Binding(“text”,"", getImportContextMenuName),
{
margin: 5,
font: pfdStyles.dataNodeFont,
alignment: go.Spot.LeftCenter,
mouseOver: highlightContextMenuItem,
mouseHover: highlightContextMenuItem
}),
new go.Binding(“visible”, “”, isImportContextButtonEnabled).ofObject()
)

It works about 60% of the time and the other times it reverts to using the default coloring. It feels like either there is another event that is firing that I have not attached the method to that causes this to happen or I am totally doing it the wrong way.

Any thoughts would be greatly appreciated.

It’s a bit odd to have both the mouseOver and the mouseHover events do the same thing. It’s also odd to have both a Panel and one of its elements have the same event handlers too. Normally one would find defining the event handler on the Panel to be sufficient, since those events bubble up the visual tree.

Sounds like you would prefer using the mouseEnter and mouseLeave events instead of mouseOver or mouseHover, probably only defined on the button/Panel.

I’m getting back to this issue. I think I have done what was suggested but I still see the problem. I created a JSFiddle for this (GoJS Context Menu - JSFiddle - Code Playground)and am pasting the code here as well. It seems to be random as I move my mouse over the context menu after right clicking to bring it up. It seems to be more reproducible when I rapidly move the mouse over one of the ContextMenuButtons from outside the context menu. Any suggestions would be greatly appreciated.

<span =“Apple-tab-span” style=“white-space:pre”> var GO = go.GraphObject.make;

var linkStrokeColor = "black";
var linkSelectionColor = GO(go.Brush, go.Brush.Solid, {"color": "#2982b9"});
var linkStrokeWidth = 2;
var dataNodeFont = "400 16px 'AvenirNext', Helvetica, Arial, sans-serif";
var contextMenuColor = GO(go.Brush, go.Brush.Solid, {"color": "lightyellow"});
var contextMenuHoverFillColor = GO(go.Brush, go.Brush.Solid, {"color": "lightgreen"});
var contextMenuHeaderBackgroundColor = GO(go.Brush, go.Brush.Solid, {"color": "pink"});
var contextMenuStrokeColor = GO(go.Brush, go.Brush.Solid, {"color": "black"});
var nodes = [
{
<span ="Apple-tab-span" style="white-space:pre">	</span>"type":"dataNode",
<span ="Apple-tab-span" style="white-space:pre">	</span>"dataType":"",
<span ="Apple-tab-span" style="white-space:pre">	</span>"id":"_9",
<span ="Apple-tab-span" style="white-space:pre">	</span>"x":300,
<span ="Apple-tab-span" style="white-space:pre">	</span>"y":100,
<span ="Apple-tab-span" style="white-space:pre">	</span>"width":29,
<span ="Apple-tab-span" style="white-space:pre">	</span>"height":38,
<span ="Apple-tab-span" style="white-space:pre">	</span>"name":"First Node",
<span ="Apple-tab-span" style="white-space:pre">	</span>"displayName":"First Node"
},
{
<span ="Apple-tab-span" style="white-space:pre">	</span>"type":"dataNode",
<span ="Apple-tab-span" style="white-space:pre">	</span>"dataType":"",
<span ="Apple-tab-span" style="white-space:pre">	</span>"id":"_10",
<span ="Apple-tab-span" style="white-space:pre">	</span>"x":300,
<span ="Apple-tab-span" style="white-space:pre">	</span>"y":200,
<span ="Apple-tab-span" style="white-space:pre">	</span>"width":29,
<span ="Apple-tab-span" style="white-space:pre">	</span>"height":38,
<span ="Apple-tab-span" style="white-space:pre">	</span>"name":"Second Node",
<span ="Apple-tab-span" style="white-space:pre">	</span>"displayName":"Second Node"
},
   {
<span ="Apple-tab-span" style="white-space:pre">	</span>"type":"dataNode",
<span ="Apple-tab-span" style="white-space:pre">	</span>"dataType":"",
<span ="Apple-tab-span" style="white-space:pre">	</span>"id":"_11",
<span ="Apple-tab-span" style="white-space:pre">	</span>"x":300,
<span ="Apple-tab-span" style="white-space:pre">	</span>"y":300,
<span ="Apple-tab-span" style="white-space:pre">	</span>"width":29,
<span ="Apple-tab-span" style="white-space:pre">	</span>"height":38,
<span ="Apple-tab-span" style="white-space:pre">	</span>"name":"Third Node",
<span ="Apple-tab-span" style="white-space:pre">	</span>"displayName":"Third Node"
},

];

var links = [

<span =“Apple-tab-span” style=“white-space:pre”> {
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “type”:“sequenceFlow”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “category”:“sequenceFlow”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “name”:“”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “from”:“_9”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “to”:“_10”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “fromPort”:“flowOutput”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “toPort”:“flowInput”
<span =“Apple-tab-span” style=“white-space:pre”> },
<span =“Apple-tab-span” style=“white-space:pre”> {
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “type”:“sequenceFlow”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “category”:“sequenceFlow”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “name”:“”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “from”:“_10”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “to”:“_11”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “fromPort”:“flowOutput”,
<span =“Apple-tab-span” style=“white-space:pre”> <span =“Apple-tab-span” style=“white-space:pre”> “toPort”:“flowInput”
<span =“Apple-tab-span” style=“white-space:pre”> }
<span =“Apple-tab-span” style=“white-space:pre”> ];

<span =“Apple-tab-span” style=“white-space:pre”> var myDiagram;
var importMenuItem = undefined;
var exportMenuItem = undefined;

<span =“Apple-tab-span” style=“white-space:pre”> function getPosition(data,node){
<span =“Apple-tab-span” style=“white-space:pre”> console.debug(“Setting location for node with name: "”+data.name+“" to (”+data.x+“,”+data.y+“)”);
<span =“Apple-tab-span” style=“white-space:pre”> return new go.Point(data.x,data.y);
}

function highlightImportContextMenuItem(event,obj) {
    console.log("highlight Import MenuItem called");
    importMenuItem = event.targetObject;
    if (importMenuItem) {
        importMenuItem.fill = contextMenuHoverFillColor;
    }
    else {
        console.log("Did not highlight Import MenuItem because the targetObject was undefined");
    }
}

function unHighlightImportContextMenuItem(event) {
    console.log("unhighlight for Import MenuItem called");
    if (importMenuItem) {
        importMenuItem.fill = contextMenuColor;
    }
    else {
        console.log("Did not unhighlight Import MenuItem because the importMenuItem was undefined");
    }
    importMenuItem = undefined;
}

function highlightExportContextMenuItem(event,obj) {
    console.log("highlight Export MenuItem called");
    exportMenuItem = event.targetObject;
    if (exportMenuItem) {
        exportMenuItem.fill = contextMenuHoverFillColor;
    }
    else {
        console.log("Did not highlight Export MenuItem because the targetObject was undefined");
    }
}

function unHighlightExportContextMenuItem(event) {
    console.log("unhighlight for Export MenuItem called");
    if (exportMenuItem) {
        exportMenuItem.fill = contextMenuColor;
    }
    else {
        console.log("Did not unhighlight Export MenuItem because the exportMenuItem was undefined");
    }
    exportMenuItem = undefined;
}

var contextMenuTemplate =
GO(go.Adornment, "Vertical", {
        margin: 1
    },
    GO(go.Panel, "Auto", {
            background: contextMenuColor
        },
        GO(go.Shape, "Rectangle", {
            fill: contextMenuHeaderBackgroundColor,
            stroke: null
        }),
        GO(go.TextBlock,
            {
                margin: 5,
                font: dataNodeFont,
                textAlign: "left",
                text: "Context Menu Header"
            }
        )
    ),
    GO("ContextMenuButton", {
            "ButtonBorder.fill": contextMenuColor,
            "ButtonBorder.stroke": contextMenuStrokeColor,

// click: exportDataset,
mouseEnter: highlightExportContextMenuItem,
mouseLeave: unHighlightExportContextMenuItem
},
GO(go.TextBlock,
{
text: “Export Data”,
margin: 5,
font: dataNodeFont,
alignment: go.Spot.LeftCenter
})
),
GO(“ContextMenuButton”,{
“ButtonBorder.fill”: contextMenuColor,
“ButtonBorder.stroke”: contextMenuStrokeColor,
// click: importDataset,
mouseEnter: highlightImportContextMenuItem,
mouseLeave: unHighlightImportContextMenuItem
},
GO(go.TextBlock,
{
text: “Import Data”,
margin: 5,
font: dataNodeFont,
alignment: go.Spot.LeftCenter
})
)
);

var dataNodeTemplate = GO(go.Node, "Vertical",
    {
        avoidable: true,
        locationObjectName: "DATA_OBJECT",
        selectionAdorned: false,
        contextMenu: contextMenuTemplate
    },
    new go.Binding("position","", getPosition),
                                      GO(go.Panel, "Vertical",
            GO(go.Shape, "RoundedRectangle",
                {
                    fill:  "yellow",
                    strokeWidth: 2,
                    stroke: "black",
                    mouseEnter: function (e, node) {
                    },
                    portId: "dataInput",
                    toSpot: go.Spot.TopCenter
                },
                new go.Binding("width", "width"),
                new go.Binding("height", "height")
        ),
        GO(go.Shape, // flowOutput
            {
                width: 0,
                height: 0,
                portId: "dataOutput",
                fromSpot: go.Spot.RightCenter,
                alignment: go.Spot.RightCenter
            }
        )
    ),
    GO(go.TextBlock,
       <span ="Apple-tab-span" style="white-space:pre">	</span>{
           <span ="Apple-tab-span" style="white-space:pre">	</span>margin: 0,
           <span ="Apple-tab-span" style="white-space:pre">	</span>editable: false,
           <span ="Apple-tab-span" style="white-space:pre">	</span>textAlign: "center",
           <span ="Apple-tab-span" style="white-space:pre">	</span>wrap: go.TextBlock.None,
           <span ="Apple-tab-span" style="white-space:pre">	</span>font: dataNodeFont
       <span ="Apple-tab-span" style="white-space:pre">	</span>},
       <span ="Apple-tab-span" style="white-space:pre">	</span>new go.Binding("text", "displayName")
   <span ="Apple-tab-span" style="white-space:pre">	</span>)
);

var sequenceLinkTemplate =
    GO(go.Link, {
            routing: go.Link.Orthogonal,
            curve: go.Link.None,
            corner: 10,
            reshapable: false,
            relinkableFrom: false,
            relinkableTo: false
        },
        GO(go.Shape, {
            isPanelMain: true,
            stroke: linkStrokeColor,
            strokeWidth: linkStrokeWidth
        }),
        GO(go.Shape, {
            toArrow: "Triangle",
            scale: 1.2,
            fill: linkStrokeColor,
            stroke: null
        }),
        {
            selectionAdornmentTemplate:
                GO(go.Adornment,
                    GO(go.Shape, {
                        isPanelMain: true,
                        stroke: linkSelectionColor,
                        strokeWidth: linkStrokeWidth
                    }),
                    GO(go.Shape, {
                        toArrow: "Triangle",
                        scale: 1.2,
                        fill: linkSelectionColor,
                        stroke: linkSelectionColor
                    })
                )
        }
    );

<span =“Apple-tab-span” style=“white-space:pre”> $(document).ready(function() {

    myDiagram = GO(go.Diagram, "myDiagram", {
        allowDelete: false,
        allowMove: false,
        allowLink: false,
        allowRelink: false,
        allowVerticalScroll: true,
        allowHorizontalScroll: true,
        hasHorizontalScrollbar: false,
        hasVerticalScrollbar: false,
        allowUndo: false,
        contentAlignment: go.Spot.Center,
        "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,
        padding: 15
    });

    var nodeTemplateMap = new go.Map("string", go.Node);
    nodeTemplateMap.add("dataNode", dataNodeTemplate);
    myDiagram.nodeTemplateMap = nodeTemplateMap;

    var linkTemplateMap = new go.Map("string", go.Link);
    linkTemplateMap.add("sequenceFlow", sequenceLinkTemplate);
    myDiagram.linkTemplateMap = linkTemplateMap;

    var model = new go.GraphLinksModel();
    model.nodeKeyProperty = 'id';
    model.nodeCategoryProperty = 'type';
    model.linkFromPortIdProperty = 'fromPort';
    model.linkToPortIdProperty = 'toPort';
    myDiagram.model = model;

    myDiagram.startTransaction('generateGraph');
    myDiagram.contentAlignment = go.Spot.Center;
    myDiagram.model.nodeDataArray = nodes;
    myDiagram.model.linkDataArray = links;
    myDiagram.zoomToFit();

    myDiagram.commitTransaction('generateGraph');

<span =“Apple-tab-span” style=“white-space:pre”> });

“Button” is already defined to have mouseEnter and mouseLeave event handlers. You can see the definitions in http://gojs.net/latest/extensions/Buttons.js (we’ve put them in the extensions directory for version 1.5). It’s OK for you to redefine them, but you might want to look at our definitions.

For what its worth, I ended up copying the original implementation as shown in your link and adding the code to modify the color there and it all works fine now.