Last active
April 16, 2016 15:22
-
-
Save unarist/2966e034b3f2995e97cd58d479a1fff1 to your computer and use it in GitHub Desktop.
マウスカーソルが乗っている文字をハイライト
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
.mask-elem { position: absolute; opacity: 0.1; z-index: -1; background: blue; } | |
.mask-node { position: absolute; opacity: 0.3; z-index: -1; background: green; } | |
.mask-char { position: absolute; opacity: 0.5; z-index: -1; background: red; } | |
</style> | |
<body> | |
<p> | |
Lorem ipsum dolor sit amet, <b>consectetur</b> adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <i>Ut</i> enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. | |
</p> | |
<p> | |
吾輩は猫である。名前はまだ無い。<u>どこで生れたか</u>とんと見当がつかぬ。<br/> | |
何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。 | |
</p> | |
<div class="mask-elem"></div> | |
<div class="mask-node"></div> | |
<div class="mask-char"></div> | |
<script> | |
document.addEventListener("mousemove", function(e){ | |
hideMask('mask-elem'); | |
hideMask('mask-node'); | |
hideMask('mask-char'); | |
var elemRange = getElementRange(e.target); | |
showMask('mask-elem', [elemRange.getBoundingClientRect()]); | |
var nodeRange = findNodeRange(elemRange, e.clientX, e.clientY); | |
showMask('mask-node', nodeRange.getClientRects()); | |
if (nodeRange.startContainer.nodeType === Node.TEXT_NODE) { | |
var charRange = findCharRange(nodeRange, e.clientX, e.clientY); | |
showMask('mask-char', charRange.getClientRects()); | |
} | |
}, true); | |
function getElementRange(element) { | |
var range = document.createRange(); | |
range.selectNodeContents(element); | |
return range; | |
} | |
function findNodeRange(elemRange, clientX, clientY) { | |
var range = elemRange.cloneRange(); | |
// childNodesから探す | |
for (var node of elemRange.startContainer.childNodes) { | |
if (node.nodeType !== Node.TEXT_NODE) continue; | |
range.selectNodeContents(node); | |
if (pointInRange(range, clientX, clientY)) | |
break; | |
} | |
if (!pointInRange(range, clientX, clientY)) | |
range.collapse(); | |
return range; | |
} | |
function findCharRange(nodeRange, clientX, clientY) { | |
range = nodeRange.cloneRange(); | |
var lc = 0; | |
while (range.endOffset - range.startOffset > 1) { | |
var s = range.startOffset, | |
e = range.endOffset, | |
mid = s + (e - s) / 2; | |
range.setEnd(range.startContainer, mid); | |
if (!pointInRange(range, clientX, clientY)) { | |
range.setStart(range.startContainer, mid); | |
range.setEnd(range.startContainer, e); | |
} | |
// 16回もやれば2^16=65536文字までいけるはずなので | |
// 超えていたら中止 | |
if (++lc >= 16) break; | |
} | |
return range; | |
} | |
function pointInRange(range, x, y) { | |
for (var rect of range.getClientRects()) | |
if (rect.left <= x && x <= rect.right && | |
rect.top <= y && y <= rect.bottom) | |
return true; | |
return false; | |
} | |
function hideMask(className) { | |
var masks = document.getElementsByClassName(className); | |
for (var mask of masks) | |
mask.style.display = "none"; | |
} | |
function showMask(className, clientRects) { | |
var masks = document.getElementsByClassName(className); | |
var maskNum = 0; | |
for (var rect of clientRects) { | |
var mask = masks[maskNum++]; | |
if (mask === undefined) { | |
mask = masks[0].cloneNode(); | |
masks[0].parentElement.appendChild(mask); | |
} | |
mask.style.display = "block"; | |
mask.style.left = (window.scrollX + rect.left) + "px"; | |
mask.style.top = (window.scrollY + rect.top) + "px"; | |
mask.style.width = rect.width + "px"; | |
mask.style.height = rect.height + "px"; | |
} | |
} | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment