How to have a link auto connect when two nodes get close

Hi,

I need to be able to show a link when two nodes get close together and if the user stops dragging create the link. What are my options?

Thanks

Create a custom DraggingTool.

  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.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) {
    if (this.copiedParts !== null) return;
    var draggednode = this.draggedParts.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) {
    if (this.copiedParts !== null) return;
    var draggednode = this.draggedParts.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)
      });
    }
  };

This makes a few assumptions about your model and your nodes – such as using a GraphLinksModel, there only being one port on each Node, and the appearance of the temporary Link. You’ll have to adapt it for your particular circumstances.

Here’s the whole test app:

  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
          {
            initialContentAlignment: go.Spot.Center,
            "undoManager.isEnabled": true,
            draggingTool: new LinkingDraggingTool()
          });

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        $(go.Shape,
          { portId: "", fromLinkable: true, toLinkable: true },
          new go.Binding("fill", "color")),
        $(go.TextBlock,
          { margin: 8 },
          new go.Binding("text"))
      );

    myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Alpha", color: "lightblue" },
      { key: 2, text: "Beta", color: "orange" },
      { key: 3, text: "Gamma", color: "lightgreen" },
      { key: 4, text: "Delta", color: "pink" }
    ]);
  }

Thanks Walter for the quick reply. I’ve implemented your sample in this fiddle and it doesn’t seem to do what I’m looking for.

Fiddle: GoJS Sample for JSFIDDLE - JSFiddle - Code Playground

What I’m wanting is when you drag a node and it gets “close enough” to another node a link will automatically be displayed connecting the two nodes. Then if:

  1. The user stops dragging while still close enough and releases the mouse button the link will be created
  2. The users drags so that the node is no longer “close enough” the link will go away

Why did you comment out the installation of the custom DraggingTool?

Oh jees, how embarrassing. I was debugging and trying to get a simple diagram to just show and forgot that code commented out. That’s perfect, thanks!

Here’s the working fiddle for future generations: GoJS Sample for JSFIDDLE - JSFiddle - Code Playground

Also, if you want a LinkingDraggingTool that works with copied nodes, see: Auto link node dragged from palette to node on canvas