Как сделать всплывающую подсказку, привязанную к разным элементам по координатам?
Всем привет! Решил модифицировать один код под свои нужды (оригинал тут: https://plnkr.co/edit/wHMgRi0DMLVtp3UU?p=preview&preview). Задача: сделать так, чтобы подсказка появлялась не у одного элемента, а у группы элементов. При этом требуется, чтобы подсказка опиралась по координатам на свой элемент. Хотя объекты создаются корректно, с нужными опорными элементами, подсказки всегда появляются по одному и тому же. Просьба пояснить, в чем причина такого поведения.
/*hoverIntent.js*/
'use strict';
class HoverIntent {
constructor({
sensitivity = 0.1, // скорость ниже 0.1px/ms значит "курсор на элементе"
interval = 100, // измеряем скорость каждые 100ms
elem,
over,
out
}) {
this.sensitivity = sensitivity;
this.interval = interval;
this.elem = elem;
this.over = over;
this.out = out;
// убедитесь, что "this" сохраняет своё значение для обработчиков.
this.onMouseMove = this.onMouseMove.bind(this);
this.onMouseOver = this.onMouseOver.bind(this);
this.onMouseOut = this.onMouseOut.bind(this);
// и в функции, измеряющей время (вызываемой из setInterval)
this.trackSpeed = this.trackSpeed.bind(this);
elem.addEventListener("mouseover", this.onMouseOver);
elem.addEventListener("mouseout", this.onMouseOut);
}
onMouseOver(event) {
if (this.isOverElement) {
// Игнорируем событие над элементом,
// так как мы уже измеряем скорость
return;
}
this.isOverElement = true;
// после каждого движения измеряем дистанцию
// между предыдущими и текущими координатами курсора
// если скорость меньше sensivity, то она считается медленной
this.prevX = event.pageX;
this.prevY = event.pageY;
this.prevTime = Date.now();
this.elem.addEventListener('mousemove', this.onMouseMove);
this.checkSpeedInterval = setInterval(this.trackSpeed, this.interval);
}
onMouseOut(event) {
// если ушли с элемента
if (!event.relatedTarget || !elem.contains(event.relatedTarget)) {
this.isOverElement = false;
this.elem.removeEventListener('mousemove', this.onMouseMove);
clearInterval(this.checkSpeedInterval);
if (this.isHover) {
// если была остановка движения на элементе
this.out.call(this.elem, event);
this.isHover = false;
}
}
}
onMouseMove(event) {
this.lastX = event.pageX;
this.lastY = event.pageY;
this.lastTime = Date.now();
}
trackSpeed() {
let speed;
if (!this.lastTime || this.lastTime == this.prevTime) {
// курсор не двигался
speed = 0;
} else {
speed = Math.sqrt(
Math.pow(this.prevX - this.lastX, 2) +
Math.pow(this.prevY - this.lastY, 2)
) / (this.lastTime - this.prevTime);
}
if (speed < this.sensitivity) {
clearInterval(this.checkSpeedInterval);
this.isHover = true;
this.over.call(this.elem, event);
} else {
// скорость высокая, запоминаем новые координаты
this.prevX = this.lastX;
this.prevY = this.lastY;
this.prevTime = this.lastTime;
}
}
destroy() {
elem.removeEventListener('mousemove', this.onMouseMove);
elem.removeEventListener('mouseover', this.onMouseOver);
elem.removeEventListener('mouseout', this.onMouseOut);
}
}
.hours {
color: red;
}
body {
margin: 0;
}
.minutes {
color: green;
}
.seconds {
color: blue;
}
.clock {
border: 1px dashed black;
padding: 5px;
display: inline-block;
background: yellow;
position: relative;
left: 0;
top: 0;
}
#tooltip {
position: absolute;
padding: 10px 20px;
border: 1px solid #b3c9ce;
border-radius: 4px;
text-align: center;
font: italic 14px/1.3 sans-serif;
color: #333;
background: #fff;
z-index: 100000;
box-shadow: 3px 3px 3px rgba(0, 0, 0, .3);
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
<script src="hoverIntent.js"></script>
</head>
<body>
<div id="elem" class="clock">
<span class="hours">12</span> :
<span class="minutes">30</span> :
<span class="seconds">00</span>
</div>
<div id="elem1" class="clock">
<span class="hours">12</span> :
<span class="minutes">20</span> :
<span class="seconds">00</span>
</div>
<div id="tooltip" hidden>Подсказка</div>
<script>
// для демо
var elems = new Array();
elems[0] = document.querySelector('#elem');
elems[1] = document.querySelector('#elem1');
var hovers = new Array();
for(var i=0; i<=1; i++)
{
var elem = elems[i];
hovers[i] = new HoverIntent({
elem,
over() {
tooltip.style.left = elem.getBoundingClientRect().left + 5 + 'px';
tooltip.style.top = elem.getBoundingClientRect().bottom + 5 + 'px';
console.log(elem);
tooltip.hidden = false;
},
out() {
tooltip.hidden = true;
}
});
}
</script>
</body>
</html>