Displaying a html div besides a node

Hi,

I have a plotted a diagram and stuck at a particular point.
I want to display a html div besides a node when that node is double clicked.

So using ObjectDoubleClicked and filtering out further I get the clicked node,
but I am stuck here, obj.location seems to give a location of node but plotting the div at that absolute position does not render the div besides that node.

Can you help me or just point to in the direction.

Please read GoJS Coordinate Systems-- Northwoods Software. Basically, you need to call Diagram.transformDocToView to get a point in viewport coordinates, i.e. within the Canvas/Div. Depending on where in the DOM you put your HTML element, you probably need to transform the point again to get the correct coordinate system.

Once you get the HTML positioned correctly, you need to move it or hide/show it as the user scrolls or zooms. Implement a “ViewportBoundsChanged” DiagramEvent listener to do that. GoJS Events -- Northwoods Software. Please also read: GoJS Legends and Titles -- Northwoods Software, although it updates a Part rather than HTML.

Hi Walter,

Thanks to your quick reply, I was able to achieve the result faster.
There was a slight change in the event instead of double click it was changed to right click so I used the custom context menu of goJs. So I used go.HTMLInfo and rendered a 2 html elements with the following code -

        let mousePt = diagram.lastInput.viewPoint;
        mousePt = diagram.transformViewToDoc(mousePt);
        let obj = diagram.findObjectAt(mousePt);

        let srcEle = $("#addSourceDiv");
        if( srcEle.length === 0 ) {
             srcEle = $("<div id='addSourceDiv' style='z-index: 10;width: 10px;height: 10px; background:red'/>");
             srcEle.appendTo('.canvas-region');
             srcEle.appendTo('.canvas-region');
        
             srcEle.on('click',function () {
                 alert("add source");
             });
        }
    
        let srcDelEle = $("#deleteSourceDiv");
        if( srcDelEle.length === 0 ) {
            srcDelEle = $("<div id='deleteSourceDiv' style='z-index: 10;width: 10px;height: 10px;background:yellow'/>");
            srcDelEle.appendTo('.canvas-region');
            srcDelEle.appendTo('.canvas-region');
    
            srcDelEle.on('click',function () {
                alert("delete source");
            });
        }
    
        let pos = obj.location.copy();
        let nodeWidth = obj.actualBounds.width;
        let nodeHeight = obj.actualBounds.height;
        
        let diagram = GoJsDiagram.getDiagramInstance();
        pos = diagram.transformDocToView( pos );
    
        srcEle.css('left', ( pos.x + nodeWidth ) + "px");
        srcEle.css('top' , ( pos.y + 10 ) + "px");
        srcEle.css('position', 'absolute');
        srcEle.show();
    
        srcDelEle.css('left', ( pos.x + nodeWidth ) + "px");
        srcDelEle.css('top' , ( pos.y + ( nodeHeight/2 + 10 ) ) + "px");
        srcDelEle.css('position', 'absolute');
        srcDelEle.show();

and in hide context menu event I just hid these 2 elements.

This rendered my node as follows -

image
(The red and yellow squares are the displayed context menu)

.

So my question to you is this the right approach or is there some other better way to achieve this ?

It seems suspicious to me that you are calling appendTo twice consecutively.

But if it works in all of the situations that you need to handle, that’s good. Do you need to handle scrolling or zooming after showing that HTML?

The appendTo is a copy paste error while posting the question.

Scrolling and zooming case ( Thank you for mentioning them, I completely forgot about them while testing ) -

My diagram properties are -

        {
            "draggingTool.dragsLink": true,
            "undoManager.isEnabled": true,
            hasHorizontalScrollbar: false,
            hasVerticalScrollbar: false,
            // have mouse wheel events zoom in and out instead of scroll up and down
            "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,
            "toolManager.holdDelay": 0,
            initialContentAlignment: go.Spot.Center,
            // when a graph is loaded at start the nodes slowly takes the place
            "animationManager.isEnabled": true,
            layout: $$(go.TreeLayout,
                       { isInitial: false, angle: 0, nodeSpacing: 100, layerSpacing: 100 })
        }

Currently when the context menu is displayed, I am not able drag my node or canvas and neither can I zoom the canvas( is this functionality by default or did I unknowingly added some property ). But there is a problem if I zoom the canvas and then open my context menu, the menu overlaps with the node.

Currently I don’t have scaling the nodes requirement, but thinking of a generic solution can these both cases be covered ?

You should start with a Point in document coordinates, not one in viewport coordinates as you did by using InputEvent.viewPoint. That document Point should be related to the Node for which you want to show some HTML. You will need to decide which spot of the node to use, and with what offset, if any.

And do you need to worry about nodes individually being resized, rescaled, or rotated?

Sorry Walter, I am did not get your solution.
The InputEvent.viewPoint was just to identify which node is being clicked.

        let pos = obj.location.copy();
        let nodeWidth = obj.actualBounds.width;
        let nodeHeight = obj.actualBounds.height;

(Here obj is my node) I thought the above three variables were the important, in the calculation. Can you please explain it a bit more( or a link that helps me understand your point )

Use the GraphObject.click event handler on your Node template to find out which node was clicked. Or use an “ObjectSingleClicked” DiagramEvent listener.

Your code is using InputEvent.viewPoint when it should be using InputEvent.documentPoint if it were good to use the InputEvent at all.

Then your code assumes that obj is a Part when it is likely to be some GraphObject within the Node. Note that location is defined only on the Part class.

Once you handle the case that obj is some GraphObject, you need to worry about converting the GraphObject.actualBounds from its containing Panel’s coordinates to document coordinates by calling GraphObject.getDocumentPoint.

You can avoid all that work by using the click handler on your Node template, because the second argument will be the clicked Node, and its actualBounds will thus be in document coordinates.