PathSegment.Line linking text

Continuing the discussion from Line Drawing using PathSegment and PathFigure:

If you want any text to be shown, you have to use a TextBlock.

Do you have a sketch showing what you want? Exactly when do you want the text to be visible: all the time, only when the part (node, link?) is selected, only when the mouse passes over the part, etc?

Yes, sure here is the sketch.

I want the text to be visible at all time. If I understood you correctly, I would need a Node containing a Shape that holds the Geometry with the PathFigure and its Path Segments. The Node would furthermore contain the TextBlock elements. Would an appropriate solution be, to hook into the onAdd method, calculate the TextBlock position, angle and distance and add the new elements to the node?

I’m concerned with the calculation of the TextBlock position, because I’d have to consider the extend of the text based on the font and it’s size. Does GoJS contain methods that support the calculation of these text metrics?

There is no general facility for managing labels on arbitrary Shapes.

However, the Link class does. You could use a bunch of static functions such as these to do so:

/**
* This static function adds a TextBlock label for a given segment on the given Link.
* @param {Link} link
* @param {number} i an integer from 0 to link.points.length-2
*/
PolylineLinkingTool.addLinkLabel = function(link, i) {
  var tb = new go.TextBlock();
  tb.segmentIndex = i;
  tb.segmentFraction = 0.5;
  tb.alignmentFocus = go.Spot.Bottom;
  tb.segmentOrientation = go.Link.OrientAlong;
  link.add(tb);
};

/**
* This static function finds the TextBlock label for a given segment.
* @param {Link} link
* @param {number} i an integer from 0 to link.points.length-2
* @return {TextBlock} with segmentIndex === i
*/
PolylineLinkingTool.findLinkLabel = function(link, i) {
  var it = link.elements;
  while (it.next()) {
    var tb = it.value;
    if (tb instanceof go.TextBlock && tb.segmentIndex === i) return tb;
  }
  return null;
}

/**
* This static function removes the TextBlock label for a given segment on the given Link.
* @param {Link} link
* @param {number} i an integer from 0 to link.points.length-2
*/
PolylineLinkingTool.removeLinkLabelAt = function(link, i) {
  var tb = PolylineLinkingTool.findLinkLabel(link, i);
  if (tb !== null) link.remove(tb);
};

/**
* This static function updates the TextBlock text for a given segment on the given Link.
* @param {Link} link
* @param {number} i an integer from 0 to link.points.length-2
*/
PolylineLinkingTool.updateLinkLabel = function(link, i) {
  var tb = PolylineLinkingTool.findLinkLabel(link, i);
  if (tb !== null && link.pointsCount >= 2) {
    var p = link.getPoint(i);
    var q = link.getPoint(i + 1);
    tb.text = Math.floor(Math.sqrt(p.distanceSquaredPoint(q))).toString();
  }
};

/**
* This static function makes sure there are TextBlock labels for all segments on the given Link.
* @param {Link} link
*/
PolylineLinkingTool.addAllLinkLabels = function(link) {
  for (var i = 0; i < link.pointsCount - 1; i++) {
    var tb = PolylineLinkingTool.findLinkLabel(link, i);
    if (tb === null) {
      PolylineLinkingTool.addLinkLabel(link, i);
    }
    PolylineLinkingTool.updateLinkLabel(link, i);
  }
};

/**
* This static function removes TextBlock labels for all segments on the given Link.
* @param {Link} link
*/
PolylineLinkingTool.removeAllLinkLabels = function(link) {
  for (var i = 0; i < link.pointsCount; i++) {
    var tb = PolylineLinkingTool.findLinkLabel(link, i);
    if (tb !== null) link.remove(tb);
  }
};

I developed these functions in the PolylineLinkingTool extension, but I’m not going to post that code here because the work is incomplete.

If you want to use this approach you’ll need to adapt your PolygonDrawingTool to be a polyline Link drawing tool instead. Also you’ll need to set DraggingTool.dragsLink to be true. Note the restriction that the DraggingTool can only drag one such Link at a time. See the Draggable Link sample.