Need to display text on twins

Hi,

Below is the twins display code which I am using in genogram application

	myDiagram.linkTemplate =  // for parent-child relationships
        $(TwinLink,  // custom routing for same birth siblings
          {
            routing: go.Link.AvoidsNodes, curviness: 10,
            layerName: "Background", selectable: false,
            fromSpot: go.Spot.Bottom, toSpot: go.Spot.Top
          },
          $(go.Shape, { strokeWidth: 2 })
        );

//custom routing for same birth siblings
function TwinLink() {
	go.Link.call(this);
}
go.Diagram.inherit(TwinLink, go.Link);

TwinLink.prototype.computePoints = function() {
	var result = go.Link.prototype.computePoints.call(this);
	var pts = this.points;
	if (pts.length >= 4) {
		var birthId = this.toNode.data["birth"];
		if (birthId) {
			var parents = this.fromNode;
			var sameBirth = 0;
			var sumX = 0;
			var it = parents.findNodesOutOf();
			while (it.next()) {
				var child = it.value;
				if (child.data["birth"] === birthId) {
					sameBirth++;
					sumX += child.location.x;
				}
			}

			if (sameBirth > 0) {
				/* sameBirth = sameBirth +50;
              sumX = sumX + 50;*/
				var midX = sumX/sameBirth;
				var oldp = pts.elt(pts.length-4);
				// pts.setElt(pts.length-3, new go.Point(midX, oldp.y));
				pts.setElt(pts.length-3, new go.Point(midX, oldp.y));


				pts.setElt(pts.length-1, pts.elt(pts.length-1));

				// for below vertical
				pts.setElt(pts.length-2, new go.Point(midX, oldp.y));


            pts.setElt(pts.length-1, pts.elt(pts.length-1));
			}
		}
	}
	
	return result;
};

// end TwinLink class


Passing Data is :

	        {key: 0, name: "Aaron",s:"FM",age:"31",div:1,relationText:"1=divorce"},
		{key: 1, name: "Alice",s:"F",age:"29"},
		{key: 2, name: "abc",s:"M",age:"20",f:0,m:1,relationText:"1=child 1"},
		{key: 3, name: "xcv",s:"M",age:"18",f:0,m:1,nla:1,relationText:"1=child 2"},
		{key: 4, name: "dfg",s:"M",age:"16",f:0,m:1,la:1,relationText:"1=child 3"},
		{key: 5, name: "qqq",s:"F",age:"12",f:0,m:1,birth:1,relationText:"1=child 4"},
		{key: 6, name: "fgr",s:"F",age:"12",f:0,m:1,birth:1,relationText:"1=child 5"}

Example for one key details as below:

{key: 2, name: "abc",s:"M",age:"20",f:0,m:1,relationText:"1=child 1"},

Here relationText represented as “1=child 1”…
(“1” is mother’s or father’s key number) = (“child 1” is text which should be displayed on the link between child and mother or father’s node).
In the above example The text “Child 1” will display at the above of child node which is key:2.
Like that I implemented code.

Same way don’t know why twins nodes are not displaying as “child 4” and “child 5”.
Is this possible to display text for twins. If yes can you please explain?

Please let me know if anything required.

That depends entirely on the node template that you are using for those children.

Hi Walter,

I don’t know how to create node template for twins. Can you please give me the node template code?

Thanks,
Prameela.D

There is no separate template for a child that is a twin or triplet. It’s just the regular template for male or female.

Hi Walter,

I am using different link templates because of using different link shapes like legally adopted, living together, biological child and twins.
Below is my code for different templates

Marriage :

myDiagram.linkTemplateMap.add("Marriage",  
			$(go.Link,
					{ isTreeLink: false,selectable: false, routing: go.Link.AvoidsNodes,isLayoutPositioned:true,curve: go.Link.JumpGap ,segmentFraction: 0.5,layerName: "Background"},//,layerName: "Background" 
					$(go.Shape, { strokeWidth: 2 },
							new go.Binding("stroke", "patt", function(f) { return (f === "") ? "black" : "transparent"; }),
							new go.Binding("pathPattern", "patt", convertPathPatternToShape)),
							$(go.TextBlock, { segmentFraction: 0.5, margin: -2,alignment: go.Spot.Top,segmentOffset: new go.Point(0, 10) }, new go.Binding("text", "relationText")), //,wrap: go.TextBlock.WrapFit, isMultiline: true,maxSize:new go.Size(150, 100)
							$(go.TextBlock, {margin: -2,alignment: go.Spot.Top,segmentOffset: new go.Point(0, -20)}, new go.Binding("text", "srelationText"))
			));

legally adopted and living together:

myDiagram.linkTemplateMap.add("NewLinkFormats",  
			$(go.Link, {selectable: false, routing: go.Link.AvoidsNodes,isLayoutPositioned:true,curve: go.Link.JumpGap,segmentFraction: 0.15 ,layerName: "Background"},//,layerName: "Background"
					$(go.Shape, { strokeWidth: 2 },
							new go.Binding("stroke", "patt", function(f) { return (f === "") ? "black" : "transparent"; }),
							new go.Binding("pathPattern", "patt", convertPathPatternToShape)),
							$(go.TextBlock, { segmentFraction: 0.5, margin: -2,segmentIndex: 2.6, segmentFraction: 0.5,alignment: go.Spot.Center,segmentOffset: new go.Point(0, -20) }, new go.Binding("text", "relationText")),//segmentOrientation: go.Link.OrientUpright
							$(go.TextBlock, { margin: -2,alignment: go.Spot.Top,segmentOffset: new go.Point(0, -10) }, new go.Binding("text", "srelationText"))
						
							
			))	 ;

Biological Child:

myDiagram.linkTemplateMap.add("ParentChild",  
			$(go.Link,
					{selectable: false, routing: go.Link.AvoidsNodes,layerName: "Background",isLayoutPositioned:true},
					$(go.Shape, { strokeWidth: 2},
							new go.Binding("stroke", "patt", function(f) { return (f === "") ? "black" : "transparent"; }),
							new go.Binding("pathPattern", "patt", convertPathPatternToShape)),
							$(go.TextBlock, { margin: 2,wrap: go.TextBlock.WrapFit, isMultiline: true,maxSize:new go.Size(90, 100),margin: -2,segmentIndex: 2.6, segmentFraction: 0.5,alignment: go.Spot.Center,segmentOffset: new go.Point(60, -60) }, new go.Binding("text", "relationText")),
							$(go.TextBlock, { margin: -2,alignment: go.Spot.Top,segmentOffset: new go.Point(0, -10)}, new go.Binding("text", "srelationText"))
			));

Twins:

myDiagram.nodeTemplateMap.add("TwinLinkLabel",
	        $(go.Node, { segmentIndex: -2, segmentFraction: 0.5, selectable: false, width: 1, height: 1, isLayoutPositioned: false }));



myDiagram.linkTemplateMap.add("Twin",  // for connecting twins/triplets
	        $(go.Link, { selectable: false, isLayoutPositioned:true,curve: go.Link.JumpGap,segmentFraction: 0.5 ,layerName: "Background" },
	          $(go.Shape, { strokeWidth: 2, stroke: "blue" }),
	          $(go.TextBlock, { segmentFraction: 0.5, margin: -2,segmentIndex: 2.6, segmentFraction: 0.5,alignment: go.Spot.Center,segmentOffset: new go.Point(0, -20) }, new go.Binding("text", "relationText")),//segmentOrientation: go.Link.OrientUpright
				$(go.TextBlock, { margin: -2,alignment: go.Spot.Top,segmentOffset: new go.Point(0, -10) }, new go.Binding("text", "srelationText"))
	      ));

For twins, I am using the below function:

function TwinDrawingTool() {
    go.LinkingTool.call(this);
  }
  go.Diagram.inherit(TwinDrawingTool, go.LinkingTool);

  TwinDrawingTool.prototype.findLinkablePort = function() {
    var diagram = this.diagram;
    if (diagram === null) return null;
    var obj = this.startObject;
    if (obj === null) {
      obj = diagram.findObjectAt(diagram.firstInput.documentPoint, null, null);
    }
    if (obj === null) return null;
    var node = obj.part;
    if (!(node instanceof Node)) return null;
    // require the node to have parents and siblings
    var parentMarriageNode = node.findTreeParentNode();
    if (parentMarriageNode === null) return null;
    if (parentMarriageNode.findTreeChildrenLinks().count <= 1) return null;
    return node.port;
  };

  TwinDrawingTool.prototype.isValidTo = function(tonode, toport) {
    if (tonode === null || toport === null) return false;
    if (tonode.data.birth !== undefined) return false;  // already a twin?
    if (tonode === this.originalFromNode) return false;  // not to itself!
    // require both the fromnode and the tonode to have the same marriage (label) parent node
    return this.originalFromNode.findTreeParentNode() === tonode.findTreeParentNode();
  };

  TwinDrawingTool.prototype.insertLink = function(fromnode, fromport, tonode, toport) {
    var diagram = this.diagram;
    if (diagram === null) return null;
    var fromParentLink = fromnode.findTreeParentLink();
    var toParentLink = tonode.findTreeParentLink();
    // assert
    if (fromParentLink === null || toParentLink === null || fromParentLink.fromNode !== toParentLink.fromNode) {
      throw new Error("this should never happen");
    }
    var commonParent = fromParentLink.fromNode;
    var model = diagram.model;
    // make sure the parent link of the fromnode has a label node; create it if needed
    var fromParentLabelNode = fromParentLink.labelNodes.first();
    var fromLabelData = null;
    if (fromParentLabelNode === null) {
      fromLabelData = { };
      model.setCategoryForNodeData(fromLabelData, "TwinLinkLabel");
      model.addNodeData(fromLabelData);  // assigns key
      model.addLabelKeyForLinkData(fromParentLink.data, model.getKeyForNodeData(fromLabelData));
    } else {
      fromLabelData = fromParentLabelNode.data;
    }
    // make sure the parent link of the tonode has a label node; create it if needed
    var toParentLabelNode = toParentLink.labelNodes.first();
    var toLabelData = null;
    if (toParentLabelNode === null) {
      toLabelData = { };
      model.setCategoryForNodeData(toLabelData, "TwinLinkLabel");
      model.addNodeData(toLabelData);  // assigns key
      model.addLabelKeyForLinkData(toParentLink.data, model.getKeyForNodeData(toLabelData));
    } else {
      toLabelData = toParentLabelNode.data;
    }
    // now that both label nodes exist, add a TwinLink between them
    var twinLinkData = {};
    model.setCategoryForLinkData(twinLinkData, "Twin");
    model.setFromKeyForLinkData(twinLinkData, model.getKeyForNodeData(fromLabelData));
    model.setToKeyForLinkData(twinLinkData, model.getKeyForNodeData(toLabelData));
    model.addLinkData(twinLinkData);
    // make sure "birth" is set on both nodes
    if (fromnode.data.birth === undefined) {
      // how many sets of twins/triplets does this marriage have already?
      var maxBirth = 0;
      commonParent.findTreeChildrenNodes().each(function(n) {
        if (n.data.birth !== undefined) {
          maxBirth = Math.max(maxBirth, n.data.birth);
        }
      })
      model.setDataProperty(fromnode.data, "birth", maxBirth + 1);
    }
    model.setDataProperty(tonode.data, "birth", fromnode.data.birth);
    return diagram.findLinkForData(twinLinkData);
  };

But displaying as below screenshot:

But I need twins to display as below with child 4 and child 5(which is not displaying text child 4 and child 5):

Thanks,
Prameela.D

Oh, you’re putting the labels on the links, not on the nodes? OK.

You seem to have two separate TextBlocks on your “Twin” link template. Is that intentional?

I suggest that you temporarily set the layerName: "Foreground" so that you can see if the labels are showing up, but just not seen because they are behind the child node.

The segmentIndex must be an integer. GraphObject | GoJS API I suggest that you use -1, indicating the last segment.

Hi Walter,

Now I am able to display text on the twins links. But not in one level as shown below:

I changed the twins code to display the text or labels.
Changed code is given below:

myDiagram.linkTemplateMap.add("Twin",  // for connecting twins/triplets
	        $(TwinLink, { routing: go.Link.AvoidsNodes,selectable: false, isLayoutPositioned:true,curve: go.Link.JumpGap,segmentFraction: 0.5 ,layerName: "Background" },
	          $(go.Shape, { strokeWidth: 2, stroke: "black" }),
	          $(go.TextBlock, { margin: -2,segmentIndex: -1, segmentFraction: 0.2,alignment: go.Spot.Bottom,segmentOffset: new go.Point(0, -20) }, new go.Binding("text", "relationText")),//segmentOrientation: go.Link.OrientUpright
				$(go.TextBlock, { margin: -2,alignment: go.Spot.Top,segmentOffset: new go.Point(0, -10) }, new go.Binding("text", "srelationText"))
	      ));


function TwinLink() {
	go.Link.call(this);
}
go.Diagram.inherit(TwinLink, go.Link);

TwinLink.prototype.computePoints = function() {
	var result = go.Link.prototype.computePoints.call(this);
	var pts = this.points;
	if (pts.length >= 4) {
		var birthId = this.toNode.data["birth"];
		if (birthId) {
			var parents = this.fromNode;
			var sameBirth = 0;
			var sumX = 0;
			var it = parents.findNodesOutOf();
			while (it.next()) {
				var child = it.value;
				if (child.data["birth"] === birthId) {
					sameBirth++;
					sumX += child.location.x;
				}
			}

			if (sameBirth > 0) {
				/* sameBirth = sameBirth +50;
              sumX = sumX + 50;*/
				var midX = sumX/sameBirth;
				var oldp = pts.elt(pts.length-4);
				// pts.setElt(pts.length-3, new go.Point(midX, oldp.y));
				pts.setElt(pts.length-3, new go.Point(midX, oldp.y));


				pts.setElt(pts.length-1, pts.elt(pts.length-1));

				// for below vertical
				pts.setElt(pts.length-2, new go.Point(midX, oldp.y));


            pts.setElt(pts.length-1, pts.elt(pts.length-1));
			}
		}
	}
	
	return result;
};

How to display Child 4,child 5 and child 6 in horizontally aligned ?

Thanks,
Prameela.D

That’s due to the segmentOffset. I suggest that you not include a Y component in that Point.

And I suggest that you set segmentFraction to 0.0 and alignmentFocus to new go.Spot(0, 1, -20, 0). You may need to fiddle with that alignmentFocus Spot to get the label where you want.

Please re-read GoJS Link Labels -- Northwoods Software.