Getting the DOM Rect(s) of a text range that may be split across lines?

Hi, I’m wondering how to get the DOM Rect or Rects, if I have a [start, end] range of a run of text that may be split over multiple lines.

My use case: I’m using the Typescript compiler to find the “closest” Expression node to the mouse position, so Typescript gives me a [start, end] range for a node’s text form.

I would like to anchor a Tooltip to this range with the Floating UI - Inline strategy, which attempts to anchor to the first DOMRect of a split inline string.

It seems like CM5 had the charCoords method, as I found in Fastest method for getting size of text range. But I haven’t found a discussion thread for a CM6 pattern, and I wasn’t able to identify something similar in the docs.

I thought about using posAtCoord(start) and posAtCoord(end) to form the rect, but this makes a box “in between” the range, not the equivalent of a split span selection.

Does CM6 offer a means of getting this inline span rect? If not, do you have suggestions for how I might otherwise measure this myself?

Thank you, Rodney

Maybe you could use lineAt(start) and lineAt(end) to get information about the lines where your range starts and ends and work from there to get the coordinates you need?

https://codemirror.net/docs/ref/#state.Text.lineAt

1 Like

No (but neither did CM5). The equivalent to charCoords is coordsAtPos, and you can use moveToLineBoundary to find the visual start/end of a line. Or use the built-in tooltip feature and let that manage tooltip positioning.

1 Like

Thanks for your suggestions! I ended up getting this to work by decorating my range:

  1. Create a new Decoration with a unique class name
  2. Decorate my range with this decorator
  3. Use document.querySelectorAll(.myClass) to get references to all DOM nodes tagged with this decoration.
  4. Get the bounding rect of each returned DOM node.
  5. Rerun the above logic when the document is modified.
    a. (floating-ui handles recalculation when the user is scrolling or other position things happen)

Does this seem like a reasonable approach? I think I can be more precise about when to rerun this check (only when another CM transaction would modify the final span of the range?). Otherwise this seems to do what I need.

That sounds like it will cause some extra relayouts, but if you want a precise list of rectangles it may be the only approach that really gives you that.

1 Like