Round-trip posAtCoords and coordsAtPos

I would like to call “coordsAtPos” to get the screen coordinates of a position (eg. the cursor), then later call “posAtCoords” to get the nearest position to those coordinates again. (eg/ to swap a document but keep a similar cursor position.)

However, I find that even without changing the document at all, ‘posAtCoords’ often doesn’t return anything close to ‘coordsAtPos’.

ProseMirror coords

Above is a gif showing the behaviour. Just for demonstration purposes, I’ve set an onClick callback to get the $cursor.pos, call posAtCoords on it, resolve that position, and then create a new selection (I tried both TextSelection and Selection.near). The cursor jumps around a lot, whereas I would expect that we could round-trip these functions to get back the same position. Maybe I am missing something with how these functions are supposed to work?

There’s a test for this here. Try to figure out what you’re doing differently.

I can’t see much difference between that test and my code, but I’ve found that if I add a few pixels to the top property returned from coordsAtPos, I can get consistent results. (To be on the safe side I am now setting top to pos.top + ((pos.bottom - pos.top) / 2)).

Could it be that the top property is sometimes-but-not-always considered outside of the bounds of the current node?

…I also see that top is returned as a float, while left is always an integer. Maybe related.

…I tried Math.ceil(top) to see if it was just an issue related to rounding, and that did not work.

I also tried using top + 1. That caused correct behaviour for some kinds of nodes, but I still saw consistently bad coordinates when clicking on a node with a larger than normal height (eg. a heading).

So far I have found consistently correct coordinates only when using a top value that is the midpoint between top and bottom as returned from coordsAtPos.

These are produced by the browser, whose rounding strategies are mysterious (and not consistent between different browsers).

The top and bottom coordinates you get will be on the very edge of the box taken up by the node, so yes, averaging them is probably a good idea if you want to be sure you get the same position back. Also, again, the library is asking the browser what is at a given position, and browsers don’t always give predictable answers when near the edges of an element.

1 Like