<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Get position of characters in textnode using Range</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="application">
<h1 id="after-text">Overlay without wrapping</h1>
<div id="characters-wrapper">
<div id="characters">Some characters1!</div>
</div>
<button id="chars">Characters</button><button id="words">Words</button>
<p id="description">*does not refresh automatically on resize :)</p>
</div>
<script src="js/index.js"></script>
</body>
</html>
/*Downloaded from https://www.codeseek.co/rosefalk/get-position-of-characters-in-textnode-using-range-yzgEEv */
/* if you want the CSS you can safely ignore everything from here */
html,body {
height: 100%;
background: #b33;
color: #333;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
#application {
text-align: center;
padding: 25px;
background: #fff;
box-shadow: 0 0 20px #000;
border-radius: 3px;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: auto;
grid-template-areas:
"after-text after-text"
"characters characters"
"button-chars button-words"
"description description";
}
#characters-wrapper {
margin: 25px;
font-size: 24px;
grid-area: characters;
}
#characters {
position: relative;
}
button {
margin: 5px;
padding: 5px;
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
background: #ececec;
border: 1px solid #bbb;
}
#chars {
grid-area: button-chars;
}
#words {
grid-area: button-words;
}
#after-text {
grid-area: after-text;
font-size: 20px;
text-transform: uppercase;
}
#description {
grid-area: description;
font-style: italic;
}
/*to here*/
.marker {
position: absolute;
box-sizing: border-box;
height: 4px;
border: 1px solid #abc;
}
/*Downloaded from https://www.codeseek.co/rosefalk/get-position-of-characters-in-textnode-using-range-yzgEEv */
function getCharacterPositions(target,word) {
var range = document.createRange(),
parentEl = document.getElementById(target).childNodes[0],
chars = parentEl.textContent.split( (word)?' ':'' ),
arrayPositions = new Array();
var start = 0,
end = 0;
for (var i = 0; i < chars.length; i++) {
var char = chars[i],
start = (word)?start:i,
end = (word)?(start+char.length):i+1;
range.setStart(parentEl, start);
range.setEnd(parentEl, end);
arrayPositions.push(range.getClientRects());
if(word) {
start = end+1;
}
}
return arrayPositions;
}
function visualize(arrayOfPositions) {
//remove old markers
var elements = document.getElementsByClassName('marker');
while(elements.length > 0){
elements[0].parentNode.removeChild(elements[0]);
}
//make new markers
for (var i = 0; i < arrayOfPositions.length; i++) {
var data = arrayOfPositions[i];
var marker = document.createElement('div')
marker.className = 'marker';
marker.style.width = data[0].width+'px';
marker.style.height = data[0].height+'px';
marker.style.left = data[0].left+'px';
marker.style.top = data[0].top+'px';
document.getElementById('characters-wrapper').appendChild(marker);
}
}
document.getElementById("chars").addEventListener("click", function( event ) {
visualize(getCharacterPositions("characters"))
}, false);
document.getElementById("words").addEventListener("click", function( event ) {
visualize(getCharacterPositions("characters",true))
}, false);