Margin of LineV shapes


I have a vertical panel containing a horizontal panel containing a LineV shape.
The line is defined as follows:

let verticalLine = new go.Shape();
verticalLine.figure = "LineV";
verticalLine.width = 1;
verticalLine.stretch = go.GraphObject.Vertical;

However, there seems to be some margin around the vertical line:

Is there any setting to get rid of the margin?
I am using a single line because I need to bind it’s visibility to some property.

The measuredBounds for a Shape will always be expanded from the Shape.geometry to account for the Shape.strokeWidth.

You could try setting the width to zero, because the default Shape.strokeWidth is 1. The width and height and desiredSize are values in the shape’s local coordinate system, before any transforms are applied and any strokeWidth is considered.

Thanks for the reply. Setting the width to 0 removed the left/right margin, but the vertical line still has some bottom/top margin:

Any idea how to remove this as well?

Maybe my approach is wrong for what I am trying to achieve.
Basically I need to visualize a step function. This is the desired result (without the dotted lines):


Input data looks like this currently (but could be adjusted as it is dynmically generated):

                time: "1:50",
                width: 70,
                edge: "full",
                position: "top"
                time: "0:20",
                edge: "top",
                position: "middle"
                time: "2:30",
                width: 200,
                edge: "bottom",
                position: "bottom"

My idea was to make a part with horizontal panels (indicated by the dotted lines). The panels would have lines on all possible locations and then bind the visibility/opacity of the lines the the model data to show only the relevant lines.
I thoght I could draw something like this and then just hide the lines/texts:

Maybe there is a better solution?

Does each segment need to be a separate Part, perhaps so that each segment can be selected and moved or deleted or colored differently?

If not, I would think it be better and easier to just have a Shape with a continuous Geometry.

Hi, the segments are static, they cannot be moved or deleted, and the color is (at least currently) always the same. I was considering a single Geometry, but how would I add the time text above each horizontal line? Just calculate the absolute position of the textboxes or is there another way?

You’ll have to add separate TextBlocks. Later today I can create a sample for you, if you want. Or you can figure it out on your own right now.

Hi, if I should just calculate the absolute position of the TextBlocks and place them within the Shape I think I am able to do this.
If there is a better solution where I can place a TextBlock relative to a Geometry PathSegment it would be great if you could provide an example.

No, you’ll need to calculate them, just as you do when you calculate the points of the line.

By the way, for anyone else reading this topic, the answer to your original question is to set Shape.strokeCap to “square”. But I think you’ll be happier with the more efficient technique of creating a single Shape with a Path Geometry running the whole way.

So there’s a single Part whose Panel.itemArray is bound to your Array of data. The Panel.itemTemplate would be a simple Panel holding a TextBlock bound to the data and with a Binding that assigns the panel’s position in the Part.

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

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
        { initialContentAlignment: go.Spot.Center }); // for v1.*

    var DX = 50;  // width of each segment
    var DY = -50; // factor to compute height of each segment; positive values need to go up, hence negative

    // Min and max of data array range is cached on data object.
    // When adding items to array, clear cache by setting one of these properties to undefined.
    function findShift(data) {
      if (data.max === undefined || data.min === undefined) {
        var max = -Infinity;
        var min = Infinity;
        var arr = data.arr;
        for (var i = 0; i < arr.length; i++) {
          var d = arr[i];
          if (d.v > max) max = d.v;
          if (d.v < min) min = d.v;
        data.max = max;
        data.min = min;
      return data.max * -DY;

    myDiagram.nodeTemplate =
      $(go.Part, "Spot",
        $(go.Shape, { fill: null },
          new go.Binding("geometry", "", function(data) {
            var range = findShift(data);
            var fig = null;
            var arr = data.arr;
            for (var i = 0; i < arr.length; i++) {
              var d = arr[i];
              var x = i * DX;
              var y = d.v * DY + range;
              if (fig === null) {
                fig = new go.PathFigure(x, y);
                fig.add(new go.PathSegment(go.PathSegment.Line, x + DX, y));
              } else {
                fig.add(new go.PathSegment(go.PathSegment.Line, x, y));
                fig.add(new go.PathSegment(go.PathSegment.Line, x + DX, y));
            return new go.Geometry().add(fig);
          new go.Binding("itemArray", "arr"),
                new go.Binding("alignment", "", function(panel) {
                  var range = findShift(;
                  return new go.Spot(0, 0, panel.itemIndex * DX + DX / 2, * DY + range - 8);
                $(go.TextBlock, new go.Binding("text"))

    myDiagram.model = new go.GraphLinksModel(
          key: 1, text: "Alpha",
          arr: [
            { text: "A34", v: 3.4 },
            { text: "B23", v: 2.3 },
            { text: "C47", v: 4.7 },
            { text: "D56", v: 5.6 }


Now I scroll up a bit and see I totally forgot that each segment could have a different width. Sorry.

This looks awesome, thanks for the example!