Strange Save Node Problem

I wont save moved position of Nodes in Diagram. But a strange Problem comes. I dont know what i can do.
When i save my Diagram to JSON the position not save and nodes N3, N8,N9,N26,N27 jumps 50% higher then before. I have the Ready Source Code added.

Sorry my bad english and thanks for help.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
</head>

<body>
    <script src="https://gojs.net/latest/release/go.js"></script>
    <script>
	
    function init() {

      const $ = go.GraphObject.make;

      myDiagram =
        $(go.Diagram, "myDiagramDiv",
          {
            initialAutoScale: go.Diagram.Uniform,
            "undoManager.isEnabled": true,
              layout: $(GenogramLayout, { direction: 270, layerSpacing: 100, linkSpacing: 25, columnSpacing: 30 })
          });
		  
      myDiagram.nodeTemplateMap.add("M",  // male
        $(go.Node, "Vertical",
		new go.Binding("position", "pos", go.Point.parse).makeTwoWay(go.Point.stringify), // Here Bind the Position of Male Nodes
          { locationSpot: go.Spot.Center, locationObjectName: "ICON", selectionObjectName: "ICON" },
          new go.Binding("opacity", "hide", h => h ? 0 : 1),
          new go.Binding("pickable", "hide", h => !h),
          $(go.Panel, "Auto",
            { name: "ICON" },
            $(go.Shape, "Rectangle",
              { width: 100, height: 100, strokeWidth: 5, fill: "#0000ff", portId: "" }),
			  $(go.TextBlock, { textAlign: "center", font: "bold 20pt Arial" }, new go.Binding("text", "n")),
          ),
        ));



      myDiagram.nodeTemplateMap.add("F",  // female
        $(go.Node, "Vertical",
		new go.Binding("position", "pos", go.Point.parse).makeTwoWay(go.Point.stringify), // Here Bind the Position of Female Nodes
          { locationSpot: go.Spot.Center, locationObjectName: "ICON", selectionObjectName: "ICON" },
          new go.Binding("opacity", "hide", h => h ? 0 : 1),
          new go.Binding("pickable", "hide", h => !h),
          $(go.Panel, "Auto",
            { name: "ICON" },
            $(go.Shape, "Rectangle",
              { width: 100, height: 100, strokeWidth: 5, fill: "#ff0000", portId: "" }),
			  $(go.TextBlock, { textAlign: "center", font: "bold 20pt Arial" }, new go.Binding("text", "n")),
          ),
        ));
		
	// the representation of each label node -- nothing shows on a Marriage Link
      myDiagram.nodeTemplateMap.add("LinkLabel",
        $(go.Node, { selectable: false, width: 1, height: 1, fromEndSegmentLength: 120 }));


      myDiagram.linkTemplate =  // for parent-child relationships
        $(go.Link,
          {
            routing: go.Link.Orthogonal, 
            layerName: "Background", 
          },
          $(go.Shape, { stroke: "#000000", strokeWidth: 4 })
        );

      myDiagram.linkTemplateMap.add("Marriage",  // for marriage relationships
        $(go.Link,
          { selectable: false, layerName: "Background" },
          $(go.Shape, { strokeWidth: 4, stroke: "#000000" })
        ));

load();

    }

  function save() {
    document.getElementById("mySavedModel").value = myDiagram.model.toJson();
    myDiagram.isModified = false;
  }
  function load() {
    myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
  }

    function findMarriage(diagram, a, b) {  // A and B are node keys
      const nodeA = diagram.findNodeForKey(a);
      const nodeB = diagram.findNodeForKey(b);
      if (nodeA !== null && nodeB !== null) {
        const it = nodeA.findLinksBetween(nodeB);  // in either direction
        while (it.next()) {
          const link = it.value;
          // Link.data.category === "Marriage" means it's a marriage relationship
          if (link.data !== null && link.data.category === "Marriage") return link;
        }
      }
      return null;
    }

    // now process the node data to determine marriages
    function setupMarriages(diagram) {
      const model = diagram.model;
      const nodeDataArray = model.nodeDataArray;
      for (let i = 0; i < nodeDataArray.length; i++) {
        const data = nodeDataArray[i];
        const key = data.key;
        let uxs = data.ux;
        if (uxs !== undefined) {
          if (typeof uxs === "number") uxs = [uxs];
          for (let j = 0; j < uxs.length; j++) {
            const wife = uxs[j];
            const wdata = model.findNodeDataForKey(wife);
            if (key === wife || !wdata || wdata.s !== "F") {
              console.log("cannot create Marriage relationship with self or unknown person " + wife);
              continue;
            }
            const link = findMarriage(diagram, key, wife);
            if (link === null) {
              // add a label node for the marriage link
              const mlab = { s: "LinkLabel" };
              model.addNodeData(mlab);
              // add the marriage link itself, also referring to the label node
              const mdata = { from: key, to: wife, labelKeys: [mlab.key], category: "Marriage" };
              model.addLinkData(mdata);
            }
          }
        }
        let virs = data.vir;
        if (virs !== undefined) {
          if (typeof virs === "number") virs = [virs];
          for (let j = 0; j < virs.length; j++) {
            const husband = virs[j];
            const hdata = model.findNodeDataForKey(husband);
            if (key === husband || !hdata || hdata.s !== "M") {
              console.log("cannot create Marriage relationship with self or unknown person " + husband);
              continue;
            }
            const link = findMarriage(diagram, key, husband);
            if (link === null) {
              // add a label node for the marriage link
              const mlab = { s: "LinkLabel" };
              model.addNodeData(mlab);
              // add the marriage link itself, also referring to the label node
              const mdata = { from: key, to: husband, labelKeys: [mlab.key], category: "Marriage" };
              model.addLinkData(mdata);
            }
          }
        }
      }
    }

    // process parent-child relationships once all marriages are known
    function setupParents(diagram) {
      const model = diagram.model;
      const nodeDataArray = model.nodeDataArray;
      for (let i = 0; i < nodeDataArray.length; i++) {
        const data = nodeDataArray[i];
        const key = data.key;
        const mother = data.m;
        const father = data.f;
        if (mother !== undefined && father !== undefined) {
          const link = findMarriage(diagram, mother, father);
          if (link === null) {
            // or warn no known mother or no known father or no known marriage between them
            console.log("unknown marriage: " + mother + " & " + father);
            continue;
          }
          const mdata = link.data;
          if (mdata.labelKeys === undefined || mdata.labelKeys[0] === undefined) continue;
          const mlabkey = mdata.labelKeys[0];
          const cdata = { from: mlabkey, to: key };
          myDiagram.model.addLinkData(cdata);
        }
      }
    }


  // A custom layout that shows the two families related to a person's parents
  class GenogramLayout extends go.LayeredDigraphLayout {
    constructor() {
      super();
      this.alignOption = go.LayeredDigraphLayout.AlignAll;
      this.initializeOption = go.LayeredDigraphLayout.InitDepthFirstIn;
      this.spouseSpacing = 30;  // minimum space between spouses
    }

    makeNetwork(coll) {
      // generate LayoutEdges for each parent-child Link
      const net = this.createNetwork();
      if (coll instanceof go.Diagram) {
        this.add(net, coll.nodes, true);
        this.add(net, coll.links, true);
      } else if (coll instanceof go.Group) {
        this.add(net, coll.memberParts, false);
      } else if (coll.iterator) {
        this.add(net, coll.iterator, false);
      }
      return net;
    }

    // internal method for creating LayeredDigraphNetwork where husband/wife pairs are represented
    // by a single LayeredDigraphVertex corresponding to the label Node on the marriage Link
    add(net, coll, nonmemberonly) {
      const horiz = this.direction == 0.0 || this.direction == 180.0;
      const multiSpousePeople = new go.Set();
      // consider all Nodes in the given collection
      const it = coll.iterator;
      while (it.next()) {
        const node = it.value;
        if (!(node instanceof go.Node)) continue;
        if (!node.isLayoutPositioned || !node.isVisible()) continue;
        if (nonmemberonly && node.containingGroup !== null) continue;
        // if it's an unmarried Node, or if it's a Link Label Node, create a LayoutVertex for it
        if (node.isLinkLabel) {
          // get marriage Link
          const link = node.labeledLink;
          const spouseA = link.fromNode;
          const spouseB = link.toNode;
          // create vertex representing both husband and wife
          const vertex = net.addNode(node);
          // now define the vertex size to be big enough to hold both spouses
          if (horiz) {
            vertex.height = spouseA.actualBounds.height + this.spouseSpacing + spouseB.actualBounds.height;
            vertex.width = Math.max(spouseA.actualBounds.width, spouseB.actualBounds.width);
            vertex.focus = new go.Point(vertex.width / 2, spouseA.actualBounds.height + this.spouseSpacing / 2);
          } else {
            vertex.width = spouseA.actualBounds.width + this.spouseSpacing + spouseB.actualBounds.width;
            vertex.height = Math.max(spouseA.actualBounds.height, spouseB.actualBounds.height);
            vertex.focus = new go.Point(spouseA.actualBounds.width + this.spouseSpacing / 2, vertex.height / 2);
          }
        } else {
          // don't add a vertex for any married person!
          // instead, code above adds label node for marriage link
          // assume a marriage Link has a label Node
          let marriages = 0;
          node.linksConnected.each(l => {
            if (l.isLabeledLink) marriages++;
          });
          if (marriages === 0) {
            net.addNode(node);
          } else if (marriages > 1) {
            multiSpousePeople.add(node);
          }
        }
      }
      // now do all Links
      it.reset();
      while (it.next()) {
        const link = it.value;
        if (!(link instanceof go.Link)) continue;
        if (!link.isLayoutPositioned || !link.isVisible()) continue;
        if (nonmemberonly && link.containingGroup !== null) continue;
        // if it's a parent-child link, add a LayoutEdge for it
        if (!link.isLabeledLink) {
          const parent = net.findVertex(link.fromNode);  // should be a label node
          const child = net.findVertex(link.toNode);
          if (child !== null) {  // an unmarried child
            net.linkVertexes(parent, child, link);
          } else {  // a married child
            link.toNode.linksConnected.each(l => {
              if (!l.isLabeledLink) return;  // if it has no label node, it's a parent-child link
              // found the Marriage Link, now get its label Node
              const mlab = l.labelNodes.first();
              // parent-child link should connect with the label node,
              // so the LayoutEdge should connect with the LayoutVertex representing the label node
              const mlabvert = net.findVertex(mlab);
              if (mlabvert !== null) {
                net.linkVertexes(parent, mlabvert, link);
              }
            });
          }
        }
      }

      while (multiSpousePeople.count > 0) {
        // find all collections of people that are indirectly married to each other
        const node = multiSpousePeople.first();
        const cohort = new go.Set();
        this.extendCohort(cohort, node);
        // then encourage them all to be the same generation by connecting them all with a common vertex
        const dummyvert = net.createVertex();
        net.addVertex(dummyvert);
        const marriages = new go.Set();
        cohort.each(n => {
          n.linksConnected.each(l => {
            marriages.add(l);
          })
        });
        marriages.each(link => {
          // find the vertex for the marriage link (i.e. for the label node)
          const mlab = link.labelNodes.first()
          const v = net.findVertex(mlab);
          if (v !== null) {
            net.linkVertexes(dummyvert, v, null);
          }
        });
        // done with these people, now see if there are any other multiple-married people
        multiSpousePeople.removeAll(cohort);
      }
    }

    // collect all of the people indirectly married with a person
    extendCohort(coll, node) {
      if (coll.has(node)) return;
      coll.add(node);
      node.linksConnected.each(l => {
        if (l.isLabeledLink) {  // if it's a marriage link, continue with both spouses
          this.extendCohort(coll, l.fromNode);
          this.extendCohort(coll, l.toNode);
        }
      });
    }

    assignLayers() {
      super.assignLayers();
      const horiz = this.direction == 0.0 || this.direction == 180.0;
      // for every vertex, record the maximum vertex width or height for the vertex's layer
      const maxsizes = [];
      this.network.vertexes.each(v => {
        const lay = v.layer;
        let max = maxsizes[lay];
        if (max === undefined) max = 0;
        const sz = (horiz ? v.width : v.height);
        if (sz > max) maxsizes[lay] = sz;
      });
      // now make sure every vertex has the maximum width or height according to which layer it is in,
      // and aligned on the left (if horizontal) or the top (if vertical)
      this.network.vertexes.each(v => {
        const lay = v.layer;
        const max = maxsizes[lay];
        if (horiz) {
          v.focus = new go.Point(0, v.height / 2);
          v.width = max;
        } else {
          v.focus = new go.Point(v.width / 2, 0);
          v.height = max;
        }
      });
      // from now on, the LayeredDigraphLayout will think that the Node is bigger than it really is
      // (other than the ones that are the widest or tallest in their respective layer).
    }

    initializeIndices() {
      super.initializeIndices();
      const vertical = this.direction === 90 || this.direction === 270;
      this.network.edges.each(e => {
        if (e.fromVertex.node && e.fromVertex.node.isLinkLabel) {
          e.portFromPos = vertical ? e.fromVertex.focusX : e.fromVertex.focusY;
        }
        if (e.toVertex.node && e.toVertex.node.isLinkLabel) {
          e.portToPos = vertical ? e.toVertex.focusX : e.toVertex.focusY;
        }
      })
    }

    commitNodes() {
      super.commitNodes();
      const horiz = this.direction == 0.0 || this.direction == 180.0;
      // position the spouses of each marriage vertex
      this.network.vertexes.each(v => {
        if (v.node === null) return;
        if (!v.node.isLinkLabel) return;
        const labnode = v.node;
        const lablink = labnode.labeledLink;
        // In case the spouses are not actually moved, we need to have the marriage link
        // position the label node, because LayoutVertex.commit() was called above on these vertexes.
        // Alternatively we could override LayoutVetex.commit to be a no-op for label node vertexes.
        lablink.invalidateRoute();
        let spouseA = lablink.fromNode;
        let spouseB = lablink.toNode;
        if (spouseA.opacity > 0 && spouseB.opacity > 0) {
          // prefer fathers on the left, mothers on the right
          if (spouseA.data.s === "F") {  // sex is female
            const temp = spouseA;
            spouseA = spouseB;
            spouseB = temp;
          }
          // see if the parents are on the desired sides, to avoid a link crossing
          const aParentsNode = this.findParentsMarriageLabelNode(spouseA);
          const bParentsNode = this.findParentsMarriageLabelNode(spouseB);
          if (aParentsNode !== null && bParentsNode !== null &&
              (horiz
                ? aParentsNode.position.x > bParentsNode.position.x
                : aParentsNode.position.y > bParentsNode.position.y)) {
            // swap the spouses
            const temp = spouseA;
            spouseA = spouseB;
            spouseB = temp;
          }
          spouseA.moveTo(v.x, v.y);
          if (horiz) {
            spouseB.moveTo(v.x, v.y + spouseA.actualBounds.height + this.spouseSpacing);
          } else {
            spouseB.moveTo(v.x + spouseA.actualBounds.width + this.spouseSpacing, v.y);
          }
        } else if (spouseA.opacity === 0) {
          const pos = horiz
            ? new go.Point(v.x, v.centerY - spouseB.actualBounds.height / 2)
            : new go.Point(v.centerX - spouseB.actualBounds.width / 2, v.y);
          spouseB.move(pos);
          if (horiz) pos.y++; else pos.x++;
          spouseA.move(pos);
        } else if (spouseB.opacity === 0) {
          const pos = horiz
            ? new go.Point(v.x, v.centerY - spouseA.actualBounds.height / 2)
            : new go.Point(v.centerX - spouseA.actualBounds.width / 2, v.y);
          spouseA.move(pos);
          if (horiz) pos.y++; else pos.x++;
          spouseB.move(pos);
        }
        lablink.ensureBounds();
      });
    }

    findParentsMarriageLabelNode(node) {
      const it = node.findNodesInto();
      while (it.next()) {
        const n = it.value;
        if (n.isLinkLabel) return n;
      }
      return null;
    }
  }
  // end GenogramLayout class

    window.addEventListener('DOMContentLoaded', init);
  </script>


  <div id="myDiagramDiv" style="background-color: #F8F8F8; border: solid 1px black; width:100%; height:700px;"></div>


<button onclick="save()">Save</button>
<button onclick="load()">Load</button>
<textarea id="mySavedModel" style="width:100%;height:230px">
{ "class": "GraphLinksModel",
  "copiesArrays": true,
  "nodeCategoryProperty": "s",
  "linkLabelKeysProperty": "labelKeys",
  "nodeDataArray": [
{"key":1,"n":"N1","s":"M","m":0,"f":0,"ux":2,"vir":0},
{"key":2,"n":"N2","s":"F","m":0,"f":0,"ux":0,"vir":1},
{"key":3,"n":"N3","s":"F","m":2,"f":1,"ux":0,"vir":0},
{"key":4,"n":"N4","s":"M","m":2,"f":1,"ux":5,"vir":0},
{"key":5,"n":"N5","s":"F","m":0,"f":0,"ux":0,"vir":4},
{"key":6,"n":"N6","s":"M","m":2,"f":1,"ux":7,"vir":0},
{"key":7,"n":"N7","s":"F","m":0,"f":0,"ux":0,"vir":6},
{"key":8,"n":"N8","s":"F","m":7,"f":6,"ux":0,"vir":0},
{"key":9,"n":"N9","s":"F","m":7,"f":6,"ux":0,"vir":0},
{"key":10,"n":"N10","s":"M","m":7,"f":6,"ux":11,"vir":0},
{"key":11,"n":"N11","s":"F","m":0,"f":0,"ux":0,"vir":10},
{"key":12,"n":"N12","s":"M","m":7,"f":6,"ux":14,"vir":0},
{"key":13,"n":"N13","s":"M","m":7,"f":6,"ux":17,"vir":0},
{"key":14,"n":"N14","s":"F","m":0,"f":0,"ux":0,"vir":12},
{"key":15,"n":"N15","s":"M","m":7,"f":6,"ux":16,"vir":0},
{"key":16,"n":"N16","s":"F","m":0,"f":0,"ux":0,"vir":15},
{"key":17,"n":"N17","s":"F","m":0,"f":0,"ux":0,"vir":13},
{"key":18,"n":"N18","s":"M","m":7,"f":6,"ux":19,"vir":0},
{"key":19,"n":"N19","s":"F","m":0,"f":0,"ux":0,"vir":18},
{"key":20,"n":"N20","s":"F","m":0,"f":0,"ux":0,"vir":21},
{"key":21,"n":"N21","s":"M","m":14,"f":12,"ux":20,"vir":0},
{"key":22,"n":"N22","s":"F","m":0,"f":0,"ux":0,"vir":23},
{"key":23,"n":"N23","s":"M","m":20,"f":21,"ux":22,"vir":0},
{"key":24,"n":"N24","s":"M","m":22,"f":23,"ux":25,"vir":0},
{"key":25,"n":"N25","s":"F","m":0,"f":0,"ux":0,"vir":24},
{"key":26,"n":"N26","s":"M","m":22,"f":23,"ux":0,"vir":0},
{"key":27,"n":"N27","s":"F","m":22,"f":23,"ux":0,"vir":0},
{"key":28,"n":"N28","s":"F","m":0,"f":0,"ux":0,"vir":29},
{"key":29,"n":"N29","s":"M","m":23,"f":24,"ux":28,"vir":0},
{"key":30,"n":"N30","s":"M","m":0,"f":0,"ux":31,"vir":0},
{"key":31,"n":"N31","s":"F","m":25,"f":24,"ux":0,"vir":30},
{"key":32,"n":"N32","s":"M","m":0,"f":0,"ux":34,"vir":0},
{"key":33,"n":"N33","s":"M","m":25,"f":24,"ux":36,"vir":0},
{"key":34,"n":"N34","s":"F","m":28,"f":29,"ux":0,"vir":32},
{"key":35,"n":"N35","s":"M","m":0,"f":0,"ux":39,"vir":0},
{"key":36,"n":"N36","s":"F","m":0,"f":0,"ux":0,"vir":33},
{"key":37,"n":"N37","s":"M","m":28,"f":29,"ux":38,"vir":0},
{"key":38,"n":"N38","s":"F","m":0,"f":0,"ux":0,"vir":37},
{"key":39,"n":"N39","s":"F","m":28,"f":29,"ux":0,"vir":35},
{"s":"LinkLabel","key":-40},
{"s":"LinkLabel","key":-41},
{"s":"LinkLabel","key":-42},
{"s":"LinkLabel","key":-43},
{"s":"LinkLabel","key":-44},
{"s":"LinkLabel","key":-45},
{"s":"LinkLabel","key":-46},
{"s":"LinkLabel","key":-47},
{"s":"LinkLabel","key":-48},
{"s":"LinkLabel","key":-49},
{"s":"LinkLabel","key":-50},
{"s":"LinkLabel","key":-51},
{"s":"LinkLabel","key":-52},
{"s":"LinkLabel","key":-53},
{"s":"LinkLabel","key":-54},
{"s":"LinkLabel","key":-55},
{"s":"LinkLabel","key":-56}
],
  "linkDataArray": [
{"from":1,"to":2,"labelKeys":[-40],"category":"Marriage"},
{"from":4,"to":5,"labelKeys":[-41],"category":"Marriage"},
{"from":6,"to":7,"labelKeys":[-42],"category":"Marriage"},
{"from":10,"to":11,"labelKeys":[-43],"category":"Marriage"},
{"from":12,"to":14,"labelKeys":[-44],"category":"Marriage"},
{"from":13,"to":17,"labelKeys":[-45],"category":"Marriage"},
{"from":15,"to":16,"labelKeys":[-46],"category":"Marriage"},
{"from":18,"to":19,"labelKeys":[-47],"category":"Marriage"},
{"from":20,"to":21,"labelKeys":[-48],"category":"Marriage"},
{"from":22,"to":23,"labelKeys":[-49],"category":"Marriage"},
{"from":24,"to":25,"labelKeys":[-50],"category":"Marriage"},
{"from":28,"to":29,"labelKeys":[-51],"category":"Marriage"},
{"from":30,"to":31,"labelKeys":[-52],"category":"Marriage"},
{"from":32,"to":34,"labelKeys":[-53],"category":"Marriage"},
{"from":33,"to":36,"labelKeys":[-54],"category":"Marriage"},
{"from":35,"to":39,"labelKeys":[-55],"category":"Marriage"},
{"from":37,"to":38,"labelKeys":[-56],"category":"Marriage"},
{"from":-40,"to":3},
{"from":-40,"to":4},
{"from":-40,"to":6},
{"from":-42,"to":8},
{"from":-42,"to":9},
{"from":-42,"to":10},
{"from":-42,"to":12},
{"from":-42,"to":13},
{"from":-42,"to":15},
{"from":-42,"to":18},
{"from":-44,"to":21},
{"from":-48,"to":23},
{"from":-49,"to":24},
{"from":-49,"to":26},
{"from":-49,"to":27},
{"from":-50,"to":31},
{"from":-50,"to":33},
{"from":-51,"to":34},
{"from":-51,"to":37},
{"from":-51,"to":39}
]}
</textarea>


</body>
</html>

You have defined a Diagram.layout. It will be performed when you load a diagram by setting Diagram.model. That’s needed when you don’t have node locations (or positions) for all of the nodes.

But when you do have that information in the model and the appropriate binding, you should set Layout.isInitial to false. That way the layout won’t be performed when you load the diagram/model.

https://gojs.net/latest/intro/layouts.html#LayoutInvalidation

Thank you Walter, this was a helpful Link.

Now i have my code changed in go.Diagram.

myDiagram =
        $(go.Diagram, "myDiagramDiv",
          {
            initialContentAlignment: go.Spot.Center, initialAutoScale: go.Diagram.Uniform,
            "undoManager.isEnabled": true,
			"ModelChanged": e => {
              if (e.isTransactionFinished) {
                document.getElementById("mySavedModel").textContent = myDiagram.model.toJson();
              }
            },
              layout: $(GenogramLayout, { direction: 270, layerSpacing: 100, linkSpacing: 25, columnSpacing: 30
				,isInitial: false
			  }),
			"InitialLayoutCompleted": e => {
			if (!e.diagram.nodes.all(n => n.location.isReal())) {
				e.diagram.layoutDiagram(true);
			}}  
          });

when i reload the site is all OK, but when i move a node and save and then press load the lines goes a strange way from the middle of the node.

I have no idea! Please help.

Thank you.

LayeredDigraphLayout normally sets the Link.fromSpot and Link.toSpot according to the direction of the layout. When the layout isn’t performed, those properties aren’t being set on all of the parent-child links. So you’ll need to do it yourself.

One way is to set those two properties in the link template:

        $(go.Link,
          {
            routing: go.Link.Orthogonal, corner: 5,
            layerName: "Background", selectable: false,
            fromSpot: go.Spot.Top, toSpot: go.Spot.Bottom  // assuming direction: 270
          },
          . . .

Nice, thats help! You are genius. Thankyou Walter.