Auto link node dragged from palette to node on canvas

Howdy,

One of my coworkers already asked a similar question and it was answered here:

We’ve implemented this and it works very well! However, we’d like to have the same functionality when dragging a new node from the palette to the canvas. I’ve attempted to set the draggingTool for the palette to the very same draggingTool referenced in the linked answer. However, that doesn’t seem to be doing the trick. Is there any way to have the same behavior with an object dragged from the palette? (Showing the blue temp link when you are near a linkable node and auto linking on a drop?)

Thanks again!

So you have installed that custom LinkingDraggingTool from that other forum topic in your target Diagram? And it works well when dragging within that diagram?

I didn’t think you would need to customize the Palette’s DraggingTool, but maybe that is needed after all. I’ll have to experiment when I get a chance.

Thanks for getting back at me so quickly. I’ve provided a fiddle that expands upon Ryans work to include a palette with the LinkingDraggingTool.

When dragging a node from the palette you don’t see a temporary link appear when you are near a linkable node, you will also see that the node does not get auto connected when you drop it near another node. I’ve attempted to leave the palettes dragging tool to its default, but thee same thing occurs.

Could be I’m missing something small, but I figured that setting the palettes draggingTool to the LinkingDraggingTool will do it.

Actually, that LinkingDraggingTool is working well. It’s just defined not to work with copied Nodes. Obviously nodes that are dragged over from another diagram are going to be copied, so clearly you need to change the LinkingDraggingTool to work with copied nodes, not just moved nodes.

That’s a trivial change in three methods. Here you go:

  function LinkingDraggingTool() {
    go.DraggingTool.call(this);
    var $ = go.GraphObject.make;
    this._tempLink =
      $(go.Link,
        { layerName: "Tool" },
        $(go.Shape, { stroke: "blue", strokeWidth: 3 }),
        $(go.Shape, { stroke: "blue", strokeWidth: 3, toArrow: "OpenTriangle" })
      );
    this._tempNode =
      $(go.Node,
        { layerName: "Tool" },
        { fromLinkable: true }
      );
  }
  go.Diagram.inherit(LinkingDraggingTool, go.DraggingTool);

  LinkingDraggingTool.prototype.doDeactivate = function() {
    go.DraggingTool.prototype.doDeactivate.call(this);
    this.diagram.remove(this._tempLink);
    this.diagram.remove(this._tempNode);
  }

  LinkingDraggingTool.prototype.findNearestNode = function(pt, draggednode) {
    var linkingTool = this.diagram.toolManager.linkingTool;
    var draggeds = (this.copiedParts !== null) ? this.copiedParts : this.draggedParts;
    var near = this.diagram.findObjectsNear(pt, 50,
      // only consider undragged Nodes for which a new link would be valid
      function(x) {
        var p = x.part;
        if (p instanceof go.Node &&
          !draggeds.contains(p) &&
          linkingTool.isValidLink(draggednode, draggednode.port, p, p.port)) return p;
        return null;
      });
    // find Node whose location is closest to PT
    var dist = Infinity;
    var nearest = null;
    near.each(function(n) {
      var d2 = n.location.distanceSquaredPoint(pt);
      if (d2 < dist) {
        dist = d2;
        nearest = n;
      }
    });
    return nearest;
  };

  LinkingDraggingTool.prototype.doDragOver = function(pt, over) {
    var draggeds = (this.copiedParts !== null) ? this.copiedParts : this.draggedParts;
    var draggednode = draggeds.first().key;
    var nearest = this.findNearestNode(pt, draggednode);
    if (nearest !== null && draggednode instanceof go.Node) {
      this._tempNode.location = nearest.actualBounds.center;
      this.diagram.add(this._tempNode);
      this._tempLink.fromNode = draggednode;
      this._tempLink.toNode = this._tempNode;
      this.diagram.add(this._tempLink);
    } else {
      this.diagram.remove(this._tempLink);
    }
  };

  LinkingDraggingTool.prototype.doDropOnto = function(pt, over) {
    var draggeds = (this.copiedParts !== null) ? this.copiedParts : this.draggedParts;
    var draggednode = draggeds.first().key;
    var nearest = this.findNearestNode(pt, draggednode);
    if (nearest !== null && draggednode instanceof go.Node) {
      // this happens within the DraggingTool's transaction
      var model = this.diagram.model;
      // assume the model is a GraphLinksModel
      model.addLinkData({
        from: model.getKeyForNodeData(draggednode.data),
        to: model.getKeyForNodeData(nearest.data)
      });
    }
  };
  // end LinkingDraggingTool

Also, you do not need to replace the Palette’s ToolManager.draggingTool.

Wow, I knew it was something simple. Walter, thanks a ton I am truly impressed with how quickly you guys respond to questions.