How to drag nodes with adornment handles

I’m creating nodes that just consist of a single line. When starting to drag from the node, links are created. This is ok. However, I can’t drag the node anymore, so I created an adorment (selection adornment template) for this purpose. The node cannot be dragged via the adornment by default.

I found that I can manually trigger the DraggingTool but I don’t know when it should be triggered since there seems to be no “mouseMove” event to subscribe to. Is there an example for dragging nodes via adornments?

It sounds as if you have made the entire Node linkable (fromLinkable and/or toLinkable set to true). That is OK, but I think you really want to set fromLinkable and toLinkable to false on some object covering some area of your Node.

If your Node consists of only a single Shape, you could add a smaller transparent Shape, perhaps in the middle of your Node, that is not linkable.

Some of the Nodes in the samples do this – search for “fromLinkable: false”.

Thanks for the quick reply! Unfortunately it is required that the whole node is linkable. Is it possible to move the node via an adornment? I found that I can manually activate the DraggingTool here.

var tool = myDiagram.toolManager.draggingTool;
tool.currentPart = ...;
myDiagram.currentTool = tool;
tool.doActivate();

The question is where to put this code when I want to react to a user starting to drag an adornment?

If the whole area of the node is “linkable”, then there is no way to distinguish between a drawing-new-link operation from a moving-that-node operation.

Yes, you can have a separate “mode” when the DraggingTool operates. But I’m saying that a mouse-down-mouse-move gesture is ambiguous as to whether the user wants to draw a new link or to move that node.

Did you see how some of the samples handled that, but making sure there was some GraphObject for which fromLinkable and toLinkable are false within the Node?

I set the port property to "" on the main shape, so I guess only this shape is linkable. The adornment does not receive any links nor can I create links by dragging from it. When I drag the adornment, I’m dragging/scrolling the diagram.

I couldn’t find a sample that had some kind of “drag handle”.

What’s your Node template?

let busbarSelectionAdornmentTemplate = $(go.Adornment, "Spot",
        $(go.Panel, "Auto",
            $(go.Shape, { stroke: "dodgerblue", strokeWidth: 2, fill: null }),
            $(go.Placeholder)),
        $(go.Panel, "Auto",
            {
                alignment: go.Spot.TopRight,
                alignmentFocus: go.Spot.BottomLeft,
            },
            $(go.Shape, "Rectangle",
                 { height: 20, width: 20, fill: "blue", strokeWidth: 1 }
            )
        )
    );

let busbarTemplate = $(go.Node, "Spot",
    {
        margin: 0,
        locationObjectName: "line",
        locationSpot: go.Spot.Center,
        selectionAdornmentTemplate: busbarSelectionAdornmentTemplate,
        selectionObjectName: "line"
    },
    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
    $(go.Panel, "Spot",
            $(go.Shape, "LineH", {
                height: 5,
                width: 150,
                position: new go.Point(0, 0),
                strokeWidth: 5,
                portId: "",
                fromSpot: go.Spot.TopBottomSides,
                toSpot: go.Spot.TopBottomSides,
                fromLinkable: true,
                toLinkable: true,
                name: "line"
            })
    )
);

If you were using the debug library and paying attention to console output, you would have seen warnings about using a “Spot” or an “Auto” Panel holding only one element. And there are two such “Spot” Panels in your template, and one in your custom adornment. (Unless you deleted elements from the template that you posted, for simplicity.)

Adornments are not Nodes (or Links), so none of the predefined Tools will treat any Adornment as if they were a Node. But there might be a way to customize the DraggingTool to pretend that the blue square should be used for dragging. We’ll have to investigate.

Try this:

  function SelectionHandledDraggingTool() {
    go.DraggingTool.call(this);
  }
  go.Diagram.inherit(SelectionHandledDraggingTool, go.DraggingTool);

  SelectionHandledDraggingTool.prototype.findDraggablePart = function() {
    var diagram = this.diagram;
    if (diagram === null) return null;
    var selad = diagram.findLayer("Adornment").findObjectAt(diagram.firstInput.documentPoint,
      function(x) { return x.part; },
      function(x) { return x instanceof go.Adornment && x.category === "Selection"; });
    if (selad !== null) {
      var part = selad.adornedPart;
      if (part.canMove() || part.canCopy()) {
        this.currentPart = part;
        return part;
      }
    }
    return go.DraggingTool.prototype.findDraggablePart.call(this);
  };

Install by replacing the standard ToolManager.draggingTool:

$(go.Diagram, . . .,
  { . . .,
    draggingTool: new SelectionHandledDraggingTool()
  })

Note also that your design has the disadvantage that it requires users to select a Node before being able to drag it.

Works like a charm. Thank you very much for your help!

Yes, there are some extra panels since I have been experimenting with different solutions. I’ll remove them.

It is in fact not a good solution that the user is not able to drag the bar without selecting it first. However, there will always be some kind of tradeoff since the shape of the node is just a single line and a link can be connected to the line at any point. Maybe a viable alternative is to always show the drag handle (as part of the node, not as an adornment). I’m currently experimenting with different solutions.