Как расположить блок под курсором который появляется при наведении?
Есть карта SVG и при наведении появляется блок div с информацией при событии mousemove
Но отцентрировать по феншую не получается ..присутствуют статические единицы от которых не знаю как избавиться
Моя попытка
Длина сниппета не позволяет и потому вставляю ссылку: https://codepen.io/topicstarter/pen/PobbbZN
const svg = document.getElementById("svg-map");
const info = document.querySelector(".info");
const child = svg.querySelectorAll("path");
svg.onmousemove = function(e) {
e = window.event;
child.forEach(function(el) {
info.style.opacity = 1;
info.innerHTML = e.target.getAttribute("title");
});
info.style.left = e.clientX - 200 + "px";
info.style.top = e.clientY + 20 + "px";
};
svg.onmouseout = function() {
info.style.opacity = "0";
};
Не получается добиться вот такого результата
Ответы (2 шт):
Позиционировать нужно по pageX/Y ибо при скролле будет ломаться. info вынес перед svg-outer, тк родитель(svg-outer) позиционирован относительно, соответственно чайлд берет отступы(left, top) относительно родителя а не верхнего левого края документа
https://codepen.io/dratovannyi/pen/KKNNaQj
const svg = document.getElementById("svg-map");
const info = document.querySelector(".info");
const child = svg.querySelectorAll("path");
svg.onmousemove = function (e) {
e = window.event;
child.forEach(function (el) {
info.style.opacity = 1;
info.innerHTML = e.target.getAttribute("title");
});
info.style.left = e.pageX - 100 + "px";
info.style.top = e.pageY + 30 + "px";
};
svg.onmouseout = function () {
info.style.opacity = "0";
};
По феншую:
let info = document.querySelector(".info");
let svg = document.querySelector("#svg-map");
/***/
// Текстовое значение / видимость определяется только один раз, на входе-выходе
// Пусть mousemove меняет только координаты.
let path = svg.querySelectorAll("path");
for (let i = 0; i < path.length; i++) {
path[i].addEventListener("mouseenter", show_info);
path[i].addEventListener("mouseleave", hide_info);
}
function show_info() {
info.textContent = this.getAttribute("title");
info.style.display = "block";
}
function hide_info() {
info.style.display = "none";
}
/***/
const INFO_WID = info.offsetWidth;
const X_MAX = window.innerWidth - INFO_WID - 20;
const X_MIN = 10;
svg.addEventListener("mousemove", function(e) {
const Y_MAX = window.innerHeight - info.offsetHeight - 5;
// Определяется тут, т.к. высота info может меняться (многострочный текст)
let x = Math.max(X_MIN, Math.min(X_MAX, e.pageX - INFO_WID / 2)); // (*1)
let y = e.pageY + (e.pageY + 20 < Y_MAX ? (20) : (-info.offsetHeight - 20)); // (*2)
info.style.left = x + "px";
info.style.top = y + "px";
});
path {
fill: #f80;
}
.info {
position: absolute;
text-align: center;
width: 200px;
background: white;
box-shadow: 1px 1px 5px #000000;
}
<svg id="svg-map" width="100%" height="180">
<path title="111" d="M 0,10 0,180 80,180 80,10"></path>
<path title="222" d="M 100,10 100,180 180,180 180,10"></path>
<path title="333" d="M 200,10 200,180 280,180 280,10"></path>
<path title="444" d="M 300,10 300,180 380,180 380,10"></path>
<path title="555" d="M 400,10 400,180 480,180 480,10"></path>
<path title="666" d="M 500,10 500,180 580,180 580,10"></path>
<path title="777" d="M 600,10 600,180 680,180 680,10"></path>
</svg>
<div class="info"></div>
(*1) Math.max(X_MIN, Math.min(X_MAX, e.pageX - INFO_WID / 2));: X_MIN, X_MAX — Ограничители, чтобы не выпускать подсказку за рамки экрана. X_MAX = window.innerWidth - INFO_WID - 20 — Блок как-раз начинает выходить за рамки, когда доходит до ширина_экрана - своя_ширина.
(*2) e.pageY + (e.pageY + 20 < Y_MAX ? (20) : (-info.offsetHeight - 20)); — немного другое, к y-координате курсора нужно добавить +20px, если подсказка не выходит за рамки экрана, или вычесть -20 - высоту_подсказки, чтобы она оказалась над курсором.
