I have a lot of text, and I'd like to know where user is hovering over exactly.
For performance reasons, I'd rather not create a million <span>
s and attaching a million event handlers to them.
Is there any way to just see which character mouse is pointing at? Or alternatively where each character is located on the screen (which then could be compared against the mouse position by bisection or something).
CodePudding user response:
I don't know of a way to get the character but you could create a milion spans with only one event listeners on the parent.
html:
<div id="parent"><span>T</span><span>E</span><span>X</span><span>T</span></div>
Js:
document.getElementById("parent").addEventListener("mouseover", (e)=>{
if(e.target.tagName.toLowerCase() == "span"){
presenter.innerHTML = e.target.innerHTML;
}else{
presenter.innerHTML = "not a character";
}
})
https://codepen.io/WilbertE/pen/MWoZaeQ
CodePudding user response:
What you could do is utilizing the Selection API of the browser.
You would first check which node the mouse is over and then check in which text node it is. In the text node, you would need to check for each character if it is under the mouse.
For this, you would use some kind of divide and conquer approach to reduce the working load.
A reliable approach might take some time to implement but here is a quick and dirty solution to illustrate how it could work, but be aware that many edge cases are missing in that example.
function isInRect(x, y, rect) {
if (x < rect.left || x >= rect.right) return false;
if (y < rect.top || y >= rect.bottom) return false;
return true;
}
function getCharAtMouse(x, y) {
// first get the element the mouse is over
const elementMouseIsOver = document.elementFromPoint(x, y);
// here you should search for the text node the mouse is over which might not be the firstChild
const textNode = elementMouseIsOver.firstChild
let data = textNode.nodeValue
// iterate over each char in the text (a divide and conquer approach would be better)
for (let i = 0; i < data.length; i ) {
// create a new selection Range
let range = new Range();
// select one char (again a divide and conquer approach would be better)
range.setStart(textNode, i);
range.setEnd(textNode, i 1);
// get the bounding rect of the client getClientRects() would be needed for divide and conquer
var rect = range.getBoundingClientRect();
// check if mouseposition is in that rect
if (isInRect(x, y, rect)) {
// just here to visualize that the range is correct
document.getSelection().removeAllRanges()
document.getSelection().addRange(range)
// if so return the char at that position
return data.charAt(i)
}
}
}
document.addEventListener('click', e => {
const x = event.clientX
const y = event.clientY
console.log(getCharAtMouse(x, y))
})
<p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>
<p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>
<p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>
<p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>
<p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>