Line.labels property missing from OJS?


#1

Hi,

I’m trying to figure out how to get the labels attached to a line using the shiny new 7.4.1 test build on El Capitan (10.11.6). According to the dictionary in the ScriptEditor, there should be a labels property along with the points property. In OJS, points is there, but labels isn’t.

In ScriptEditor, the following works great:

var app = Application('OmniGraffle');
var line = app.windows[0].selection()[0];
line.labels[0].text()

However, in OJS, I get the following:

var line = document.windows[0].selection.graphics;
undefined
line
[object Line]
line.labels[0].text
// // TypeError: undefined is not an object (evaluating 'line.labels') undefined:1
line.labels();
// // TypeError: line.labels is not a function. (In 'line.labels()', 'line.labels' is undefined) undefined:1

Just an oversight?

I also noticed (by accident) that the Copy as Javascript command doesn’t copy the line labels either. The line and points are there, but the label is not, even though the line is selected and any other “copy” operation on the line brings the label with it.

I’m trying to process a drawing with a lot of labeled connections, and it’s somewhat difficult if I can’t interrogate the labels.

Any ideas appreciated!

Cheers,

ast


#2

Thanks – I hadn’t noticed that gap in the API – important to flag it through Help > Contact Omni, I think.

This is what I am seeing from a full API dump of a label attached to a line – could be missing something, but I can’t see any property encoding that relationship to the line:

Click disclosure triangles for:

omniJS property dictionary of a line label
{
    "id": 27,
    "type": "Shape",
    "actionURL": null,
    "alignsEdgesToGrid": true,
    "allowsConnections": true,
    "automationAction": [],
    "autosizing": "TextAutosizing.Full",
    "blendColor": null,
    "blendFraction": 0,
    "connectedLines": [],
    "cornerRadius": 0,
    "fillColor": {
      "r": 1,
      "g": 1,
      "b": 1,
      "a": 1
    },
    "fillType": "FillType.Solid",
    "flippedHorizontally": false,
    "flippedVertically": false,
    "fontName": "HelveticaNeue",
    "geometry": {
      "x": -106.36727182239987,
      "y": -193.3825628085692,
      "width": 85,
      "height": 30
    },
    "gradientAngle": 90,
    "gradientCenter": {
      "x": 0,
      "y": 0
    },
    "gradientColor": {
      "r": 0.20000000298023224,
      "g": 0.20000000298023224,
      "b": 0.20000000298023224,
      "a": 1
    },
    "image": null,
    "imageOffset": {
      "x": 0,
      "y": 0
    },
    "imageOpacity": 0,
    "imagePage": 0,
    "imageSizing": "ImageSizing.Manual",
    "incomingLines": [],
    "layer": "Layer 1",
    "locked": false,
    "magnets": [],
    "name": null,
    "notes": "",
    "outgoingLines": [],
    "plasticCurve": null,
    "plasticHighlightAngle": null,
    "rotation": 0,
    "shadowColor": null,
    "shadowFuzziness": 3,
    "shadowVector": {
      "x": 0,
      "y": 2
    },
    "shape": "Rectangle",
    "shapeControlPoints": [
      {
        "x": -106.36727182239989,
        "y": -193.3825628085692
      },
      {
        "x": -106.36727182239989,
        "y": -193.3825628085692
      },
      {
        "x": -21.36727182239988,
        "y": -193.3825628085692
      },
      {
        "x": -21.36727182239988,
        "y": -193.3825628085692
      },
      {
        "x": -21.36727182239988,
        "y": -193.3825628085692
      },
      {
        "x": -21.36727182239988,
        "y": -163.3825628085692
      },
      {
        "x": -21.36727182239988,
        "y": -163.3825628085692
      },
      {
        "x": -21.36727182239988,
        "y": -163.3825628085692
      },
      {
        "x": -106.36727182239989,
        "y": -163.3825628085692
      },
      {
        "x": -106.36727182239989,
        "y": -163.3825628085692
      },
      {
        "x": -106.36727182239989,
        "y": -163.3825628085692
      },
      {
        "x": -106.36727182239989,
        "y": -193.3825628085692
      }
    ],
    "shapeVertices": [
      {
        "x": -106.36727182239989,
        "y": -193.3825628085692
      },
      {
        "x": -21.36727182239988,
        "y": -193.3825628085692
      },
      {
        "x": -21.36727182239988,
        "y": -163.3825628085692
      },
      {
        "x": -106.36727182239989,
        "y": -163.3825628085692
      }
    ],
    "strokeCap": "LineCap.Round",
    "strokeColor": null,
    "strokeJoin": "LineJoin.Round",
    "strokePattern": "StrokeDash.Solid",
    "strokeThickness": 1,
    "strokeType": null,
    "text": "Label here",
    "textColor": {
      "r": 0,
      "g": 0,
      "b": 0,
      "a": 1
    },
    "textGeometry": {
      "x": -106.21127182239987,
      "y": -191.8305608554442,
      "width": 84.68799999999999,
      "height": 28.447998046875
    },
    "textHorizontalAlignment": "HorizontalTextAlignment.Center",
    "textHorizontalPadding": 5,
    "textRotation": 0,
    "textRotationIsRelative": true,
    "textSize": 16,
    "textUnitRect": {
      "x": 0,
      "y": 0,
      "width": 1,
      "height": 1
    },
    "textVerticalPadding": 5,
    "textVerticalPlacement": "VerticalTextPlacement.Middle",
    "textWraps": false,
    "tripleBlend": false,
    "userData": {}
  }

```[/details]


[details=omniJS properties of line to which label is attached]```JavaScript
{
    "id": 4,
    "type": "Line",
    "actionURL": null,
    "alignsEdgesToGrid": true,
    "allowsConnections": true,
    "automationAction": [],
    "bezierPoints": [],
    "connectedLines": [],
    "cornerRadius": 0,
    "flippedHorizontally": false,
    "flippedVertically": false,
    "geometry": {
      "x": -189.92118503021285,
      "y": -205.5116406833829,
      "width": 218.7637814307776,
      "height": 64.01540393036822
    },
    "head": 5,
    "headMagnet": 0,
    "headScale": 1,
    "headType": "FilledArrow",
    "hopType": "HopType.None",
    "incomingLines": [],
    "layer": "Layer 1",
    "lineType": "LineType.Straight",
    "locked": false,
    "name": null,
    "notes": "",
    "outgoingLines": [],
    "plasticCurve": null,
    "plasticHighlightAngle": null,
    "points": [
      {
        "x": 28.842596400564773,
        "y": -205.5116406833829
      },
      {
        "x": -189.92118503021285,
        "y": -141.49623675301467
      }
    ],
    "rotation": 0,
    "shadowColor": null,
    "shadowFuzziness": 3,
    "shadowVector": {
      "x": 0,
      "y": 2
    },
    "strokeCap": "LineCap.Round",
    "strokeColor": {
      "r": 1,
      "g": 0.149131,
      "b": 0,
      "a": 1
    },
    "strokeJoin": "LineJoin.Round",
    "strokePattern": "StrokeDash.Solid",
    "strokeThickness": 2,
    "strokeType": "StrokeType.Single",
    "tail": 3,
    "tailMagnet": 0,
    "tailScale": 1,
    "tailType": "",
    "userData": {}
  }
```[/details]

For contrast -  JXA with .labelOffset | ...Rotation | ...Position:

[details=JXA properties of line and label]```JavaScript
[
  {
    "sidePadding": 5,
    "blendColor": null,
    "tag": null,
    "cornerRadius": 0,
    "userName": null,
    "blendFraction": 0.5,
    "name": "Rectangle",
    "fill": "solid fill",
    "gradientAngle": 90,
    "drawsStroke": false,
    "strokePattern": 0,
    "startangle": 0,
    "innerradius": 0,
    "starpoints": 0,
    "labeloffset": 0,
    "strokeCap": "round",
    "id": 29,
    "shaftHeight": 0,
    "drawsShadow": false,
    "autosizing": "full",
    "shadowFuzziness": 3,
    "text": "Label here",
    "imageScale": 0,
    "textrotation": 0,
    "rankGroup": null,
    "textPlacement": "center",
    "rotation": 0,
    "endangle": 0,
    "interlineSpacing": 0,
    "allowsConnections": true,
    "locked": false,
    "alignsEdgesToGrid": true,
    "relativeTextRotation": true,
    "arrowWidth": 0,
    "intercharacterSpacing": 0,
    "notes": null,
    "url": null,
    "gradientColor": [
      0.15056076645851135,
      0.15054550766944885,
      0.15056076645851135
    ],
    "flippedHorizontally": false,
    "magnets": [],
    "labelrotation": "horizontal",
    "strokeJoin": "round",
    "script": null,
    "thickness": 1,
    "userData": null,
    "jump": null,
    "pointList": null,
    "shadowColor": [
      0,
      0,
      0
    ],
    "strokeColor": [
      0,
      0,
      0
    ],
    "verticalPadding": 5,
    "doubleStroke": false,
    "group": null,
    "flippedVertically": false,
    "shadowBeneath": false,
    "fillColor": [
      1,
      0.999969482421875,
      0.9999847412109375
    ],
    "labelposition": 0.4237898290157318,
    "imageSizing": "manual",
    "image": null,
    "class": "shape"
  },
  {
    "pointList": [
      [
        544.7480363569863,
        360.0000032663345
      ],
      [
        325.9842549262084,
        424.01540719670265
      ]
    ],
    "bezierPointList": null,
    "destination": null,
    "drawsShadow": false,
    "notes": null,
    "flippedHorizontally": false,
    "strokeCap": "round",
    "thickness": 2,
    "tag": null,
    "tailScale": 1,
    "id": 28,
    "jump": null,
    "headMagnet": 0,
    "hopType": "no hop",
    "userData": null,
    "allowsConnections": true,
    "strokeJoin": "round",
    "rankGroup": null,
    "strokeColor": [
      0.9862363338470459,
      0.007110704202204943,
      0.027420463040471077
    ],
    "class": "line",
    "tailMagnet": 0,
    "shadowBeneath": false,
    "cornerRadius": 0,
    "doubleStroke": false,
    "shadowFuzziness": 3,
    "alignsEdgesToGrid": true,
    "headType": "FilledArrow",
    "group": null,
    "flippedVertically": false,
    "shadowColor": [
      0,
      0,
      0
    ],
    "headScale": 1,
    "url": null,
    "drawsStroke": true,
    "userName": null,
    "source": null,
    "strokePattern": 0,
    "tailType": null,
    "script": null,
    "locked": false
  }
]

#3

As for interim workarounds – looks a bit tough – querying labels and detecting their relationships with particular lines is the kind of thing you really do need an API for.

Perhaps by raw geometry ? Intersect of a textGeometry Rect with some subset of the points along a line ?

( Also a pity not to be able to create line ⇄ links of the kind that move the label when the line is repositioned )

To find the presence/absence of an intersect between a connection line and one of the corner-to-corner lines of a label’s .textUnitRect or .textGeometry, here is a slightly clumsy translation to ES5 of an ES6 line intersection function which I pasted to Rosetta Code a while back.

The return value is a dictionary which either has a ‘nothing’ key set to true (no intersect - parallel) or a ‘just’ key with the coordinates of the intersection. I suppose you would have to test whether the location of any intersect was in the zone of interest, and I think some of Rect methods should lend themselves to that.

[details=JS Code]```JavaScript
(function () {
// INTERSECTION OF TWO LINES ----------------------------------------------

// maybeIntersection :: Line -> Line -> Maybe Point
var maybeIntersection = function maybeIntersection(axaybxby, pxpyqxqy) {
    var axay = axaybxby[0],
        bxby = axaybxby[1],
        pxpy = pxpyqxqy[0],
        qxqy = pxpyqxqy[1],
        ax = axay[0],
        ay = axay[1],
        bx = bxby[0],
        by = bxby[1],
        px = pxpy[0],
        py = pxpy[1],
        qx = qxqy[0],
        qy = qxqy[1],
        abDX = ax - bx,
        pqDX = px - qx,
        abDY = ay - by,
        pqDY = py - qy,
        determinant = abDX * pqDY - abDY * pqDX;

    return determinant !== 0 ? {
        nothing: false,
        just: function () {
            var abD = ax * by - ay * bx,
                pqD = px * qy - py * qx;
            return ap([function (pqab) {
                return (abD * pqab[0] - pqab[1] * pqD) / determinant;
            }], [
                [pqDX, abDX],
                [pqDY, abDY]
            ]);
        }()
    } : {
        nothing: true
    };
};

// GENERIC FUNCTIONS ------------------------------------------------------

// A list of functions applied to a list of arguments
// <*> :: [(a -> b)] -> [a] -> [b]
var ap = function ap(fs, xs) {
    return ( //
        [].concat.apply([], fs.map(function (f) {
            return ( //
                [].concat.apply([], xs.map(function (x) {
                    return [f(x)];
                }))
            );
        }))
    );
};

// show :: a -> String
var show = function show(x) {
    return JSON.stringify(x);
}; //, null, 2);

// TEST -------------------------------------------------------------------

// ab :: Line
var ab = [
    [4.0, 0.0],
    [6.0, 10.0]
];

// pq :: Line
var pq = [
    [0.0, 3.0],
    [10.0, 7.0]
];

// intersection :: Maybe Point
var intersection = maybeIntersection(ab, pq);

return intersection.nothing ? '(Parallel lines – no intersection)' : show(intersection.just);

})();


#4

( I actually can’t, for the moment, see any distinction in the API between a label and any other kind of shape that has text and happens to be near a line … i.e. no clue to which shapes will travel with a line when it moves, and which will stay behind … I guess they will tend, in most cases, to have textUnitRect values of:

"textUnitRect": {
  "x": 0,
  "y": 0,
  "width": 1,
  "height": 1
}

but that only narrows the field, and may not be reliable …

JXA / AppleScript may still be the tool(s) to reach for when line labels are used … )


#5

Thanks for that.

Yeah, I sent the email to Omni directly, and, as you say, apart from doing it through JXA, I don’t see how to do what I need to do.

I really need this and URL POST support to make things clean with what I’m trying to do.

Cheers,

ast


#6

Sorry, yes, this is missing right now. We’ll try to get this into 7.5’s test builds this week.


#7

Hi Ken,

That’s great. It’ll be a huge help.

Thanks!


#8

Any luck with (or prospect of) an interface to Line Labels ?

( The AppleScript / JavaScript for Automation interface to labels looks like quite a good model )


#9

Nudging this thread. Any updates on this topic?


#10

Probably worth a post to support, through OG > Help > Concat Omni …

This morning, looking at OG 7.71, the Line object properties are:

[ head, headMagnet, headScale, headType, tail, tailMagnet, tailScale,
tailType, lineType, hopType, points, bezierPoints ]

(No obvious sign of an interface to line labels)

and a label object seems to be a Common or Garden Shape, without further specialisation.


#11

Checked with v7.8, and still no line labels :( Bumping here, and will bump support too.


#12

Hi folks! Just a reminder that we log feature requests via our email support queue (noticed that @azaroth42 is the first to write to us since we filed this feature request back in July 2017. If you’d like to submit your +1 to that feature request, please feel free to reach out to us at omnigraffle@omnigroup.com and well get you added right away. Thanks!


#13

+1 for adding a Line property for the labels


#14

Ken reported a plan to include it in a July 2017 build:

Perhaps that proved technically difficult ?

( The impression that it was in hand may have discouraged further feature requests )


Canvas.layout() is asynchronous?
#15

Just noticed this was still not present, and so sent an email to omni support @SupportHumans, please make sure this has the appropriate feature request count. It’s quite annoying that you can’t get the text to qualify the type of line relationships when cycling through them.

Cheers,

ast


#16

( I don’t think that our cries of pain are necessarily audible from this forum – mainly positioned as peer-to-peer – important to flag these things from the app itself through Help > Contact Omni … )

( The Twitter channels can be quite responsive too )


#17

Yeah, I know… ;) Have done that too. Trying to cover all the bases. Hadn’t hit twitter, though…

Who do I request for an invite to Slack?


#18

I think you can submit an email here:

https://www.omnigroup.com/slack/


#19

And here I was looking on the slack login page. Didn’t occur to me to check from the main website. Doh!

Thanks, mate!