At least you have 2 solutions to get a charater (and related position) in some element's text under the mouse cursor. The first is to wrap each character in a <span>
or some other element, attaching some click event handler for the <span>
element and you've done. The second is to use the methods related to the Range
object (which is of course supported only by pure JS). I would like to use the first approach because it's much faster. Using Range
approach requires looping each time you click, clicking at the end of a large text may cause some bad performance. For the virtual caret, you can create some inline-block element, render the caret on it (such as by using border in combination with linear-gradient background, ...) even a transparent png image can help. Because it requires a space to render the caret, you can use negative margin (for left and right) to draw text at both sides close together. Here is the code detail:
HTML:
<div class='inter-letters'>Click on one of the characters ...</div>
CSS:
.v-caret {
width:.5em;
height:1em;
border-top:1px solid currentColor;
border-bottom:1px solid currentColor;
background:linear-gradient(to right, transparent .23em, currentColor .25em, transparent .27em);
display:inline-block;
vertical-align:middle;
margin:0 -.2em;
display:none;
}
.inter-letters {
font-size:30px;
color:green;
}
JS:
$('.inter-letters').on('click','span.letter', function(){
virtualCaret.css('display','inline-block');
$(this).after(virtualCaret);
}).html(function(i,oldhtml){
return oldhtml.replace(/./g,"<span class='letter'>$&</span>");
});
var virtualCaret = $('<div>').addClass('v-caret').appendTo('.inter-letters');
//clicking outside the div should hide the virtual caret
$(document).click(function(e){
if(!$('.inter-letters').has(e.target).length) {
virtualCaret.css('display','none');
}
});