What is a simple way to get a live caret x and y position? I've seen answers about how to get it's index position, but not x and y that updates as you type. What is the best way to do this with JQuery?
Asked
Active
Viewed 190 times
-2
-
You need to add a keyup event listener to target the div. Every time a key up event is triggered, you call the method that gets the position. – Bren Jul 09 '20 at 03:12
-
Does this answer your question? [Get contentEditable caret index position](https://stackoverflow.com/questions/3972014/get-contenteditable-caret-index-position) – Bren Jul 09 '20 at 03:14
-
@Bren Unfortunately not. I want the x and y position. – wk3456 Jul 09 '20 at 03:17
-
Physical location relative to what, the div, the entire DOM viewport? Are you just trying to get the line and column number? – Bren Jul 09 '20 at 03:31
-
@Bren the entire viewport – wk3456 Jul 09 '20 at 03:50
-
Unless you used a monospaced font, I can't imagine how it would be accurate. My first thought would be to have a dummy element that is 1rem dimensions and use javascript to get the physical dimensions of that dummy element. Then refer to the other solution I linked above. Then you'll need to compensate for where the div is located in the viewport and add those values appropriately. – Bren Jul 09 '20 at 03:53
1 Answers
-2
I found this code on a GitHub project. I hope it is what you needed.
// The properties that we copy into a mirrored div.
// Note that some browsers, such as Firefox,
// do not concatenate properties, i.e. padding-top, bottom etc. -> padding,
// so we have to do every single property specifically.
var properties = [
'boxSizing',
'width', // on Chrome and IE, exclude the scrollbar, so the mirror div wraps exactly as the textarea does
'height',
'overflowX',
'overflowY', // copy the scrollbar for IE
'borderTopWidth',
'borderRightWidth',
'borderBottomWidth',
'borderLeftWidth',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
// https://developer.mozilla.org/en-US/docs/Web/CSS/font
'fontStyle',
'fontVariant',
'fontWeight',
'fontStretch',
'fontSize',
'lineHeight',
'fontFamily',
'textAlign',
'textTransform',
'textIndent',
'textDecoration', // might not make a difference, but better be safe
'letterSpacing',
'wordSpacing'
];
var isFirefox = !(window.mozInnerScreenX == null);
var mirrorDivDisplayCheckbox = document.getElementById('mirrorDivDisplay');
var mirrorDiv, computed, style;
getCaretCoordinates = function (element, position) {
// mirrored div
mirrorDiv = document.getElementById(element.nodeName + '--mirror-div');
if (!mirrorDiv) {
mirrorDiv = document.createElement('div');
mirrorDiv.id = element.nodeName + '--mirror-div';
document.body.appendChild(mirrorDiv);
}
style = mirrorDiv.style;
computed = getComputedStyle(element);
// default textarea styles
style.whiteSpace = 'pre-wrap';
if (element.nodeName !== 'INPUT')
style.wordWrap = 'break-word'; // only for textarea-s
// position off-screen
style.position = 'absolute'; // required to return coordinates properly
style.top = element.offsetTop + parseInt(computed.borderTopWidth) + 'px';
style.left = "400px";
style.visibility = mirrorDivDisplayCheckbox.checked ? 'visible' : 'hidden'; // not 'display: none' because we want rendering
// transfer the element's properties to the div
properties.forEach(function (prop) {
style[prop] = computed[prop];
});
if (isFirefox) {
style.width = parseInt(computed.width) - 2 + 'px' // Firefox adds 2 pixels to the padding - https://bugzilla.mozilla.org/show_bug.cgi?id=753662
// Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275
if (element.scrollHeight > parseInt(computed.height))
style.overflowY = 'scroll';
} else {
style.overflow = 'hidden'; // for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'
}
mirrorDiv.textContent = element.value.substring(0, position);
// the second special handling for input type="text" vs textarea: spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037
if (element.nodeName === 'INPUT')
mirrorDiv.textContent = mirrorDiv.textContent.replace(/\s/g, "\u00a0");
var span = document.createElement('span');
// Wrapping must be replicated *exactly*, including when a long word gets
// onto the next line, with whitespace at the end of the line before (#7).
// The *only* reliable way to do that is to copy the *entire* rest of the
// textarea's content into the <span> created at the caret position.
// for inputs, just '.' would be enough, but why bother?
span.textContent = element.value.substring(position) || '.'; // || because a completely empty faux span doesn't render at all
span.style.backgroundColor = "lightgrey";
mirrorDiv.appendChild(span);
var coordinates = {
top: span.offsetTop + parseInt(computed['borderTopWidth']),
left: span.offsetLeft + parseInt(computed['borderLeftWidth'])
};
return coordinates;
}
<p>Click anywhere in the text to see a red vertical line – a 1-pixel div that should be positioned exactly at the location of the caret. Th eposition of the caret will be logged in the console.</p>
<hr>
<input type="text" size="15" maxlength="240" placeholder="Enter text here">
<hr>
<textarea rows="25" cols="40"></textarea>
<br>
<label>
<input type="checkbox" id="mirrorDivDisplay" onchange="toggleMirrorDivDisplay(this)">Show mirror div
</label>

topsoftwarepro
- 773
- 5
- 19