How to get position (left, top) of every characters in some node? I know just one method: wrap every character in it's own tag and then we can get it's coordinate. But it's bit slowly
-
I fear you don't have much choice except the method you described. To know the position of every character you must know the exact size of each letter and that's pretty much impossible task as each font has different size for each character.. – Shadow The GPT Wizard Nov 30 '10 at 09:00
-
Possible duplicate: http://stackoverflow.com/questions/5143534/get-the-position-of-text-within-an-element – Anderson Green Jun 03 '13 at 23:12
2 Answers
I've found answer on my question — Range interface can present all information that I need (More info — http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html).

- 2,477
- 1
- 18
- 31
-
1code for doing this can be find here: https://stackoverflow.com/a/29903556/142317 – Shaun Lebron Aug 14 '17 at 18:20
You could cache the widths of characters that you already have seen.
function findOffset(index) {
// Set some variables early on
var sizes = {},
text = "The text you are getting an offset from.",
lineHeight = 16, // You can get this dynamically if you want
containerWidth = 500, // Same with this one
leftOffset = 0,
topOffset = 0,
i = 0,
cur;
// Loop through and count up the sizes of each character until this one
for (; (i < text.length) && (i <= index); i++) {
// Set the current character
cur = text.charAt(i);
// Check to see if we have a size
if ( typeof size[cur] == "undefined" ) {
// If not: Wrap it in a span (You seemed to already know how to do this)
// then cache the result
size[cur] = findWidthByTemporarilyWrappingInASpan(text, i);
}
// If it's greater than a line can hold, we'll wrap
if ( (sizes[cur] + leftOffset) > containerWidth ) {
// Reset the left offset
leftOffset = 0;
// Increment the top offset
topOffset += lineHeight;
}
// Otherwise, increment from the left
else {
leftOffset += sizes[cur];
}
}
// return an object with the coordinates
return {
leftOffset: leftOffset,
topOffset : topOffset
};
}
Then you can even memoize each index that you go grab and start from a close by one the next time you call this function. This means you stay off the dom except for usually not too much more than ~50 (alphanumeric + punctuation, etc) times, rather than for each character.
This would certainly work for monospaced fonts, but I think there is some merit to it for other types. You'd just have to do the wrapping research for different browsers.
Also, note that this assumes left-justification, etc. It's more of an idea than an actual code solution.

- 10,401
- 2
- 29
- 41
-
Good idea, need to take into account the font family and font size (probably can be found with jQuery?) and add that to the cache key e.g. typical key will be "G_Tahoma_14" and another one "G_Tahoma_12". :) – Shadow The GPT Wizard Nov 30 '10 at 09:14
-
1As I mention using Range object solve my problem and it much faster than wrapping every symbol in span node. – anton_byrna Dec 20 '12 at 11:30