// Dymki na kosmogramie — własne, zamiast natywnych z (PRE-12/PRE-25). // // DLACZEGO NIE ZOSTAWIAMY NATYWNYCH. Rysunek niesie <title> przy każdym obiekcie // i każdej linii aspektu i to wystarczało, dopóki koło było statyczne. Po dodaniu // powiększania na pełne okno dymki przestały się pokazywać — a niezależnie od tego, // która reguła przeglądarki je tłumi, natywny dymek i tak jest tu kiepskim // narzędziem: pojawia się po sekundzie zwłoki, nie da się go stylować, nie działa // na dotyku i nie ma go czym wywołać z klawiatury. // // Sprawdzone w przeglądarce (1280×900, komplet 13 systemów): elementy z <title> // SĄ osiągalne kursorem — 19 z 20 trafień w hit-teście — więc nic ich nie zasłania // i problem nie leży w geometrii ani w pointer-events. // // <title> ZOSTAJE w rysunku: to nazwa dostępna dla czytników ekranu, a PDF składa // się po stronie serwera, więc ta ścieżka jest nietknięta. Na czas najechania // odpinamy go i wieszamy z powrotem po zejściu kursora — dzięki temu nigdy nie // widać dwóch dymków naraz, gdyby przeglądarka jednak swój pokazała. (function () { 'use strict'; var OFFSET = 14; // odsunięcie od kursora, żeby dymek nie siedział pod nim var stash = null; // { owner, node } — odpięty <title> do przywieszenia function ready(fn) { if (document.readyState !== 'loading') fn(); else document.addEventListener('DOMContentLoaded', fn); } ready(function () { var wheels = document.querySelectorAll('svg.wheel'); if (!wheels.length) return; var tip = document.createElement('div'); tip.className = 'wheel-tip'; tip.setAttribute('role', 'tooltip'); tip.hidden = true; document.body.appendChild(tip); function restore() { if (!stash) return; stash.owner.appendChild(stash.node); stash = null; } function hide() { tip.hidden = true; restore(); } // Element z własnym <title>, licząc od celu zdarzenia w górę. Aspekty to // cienkie linie, a glify siedzą w <text> — oba trzymają <title> jako dziecko. function owner(el, root) { while (el && el !== root) { if (el.querySelector && el.querySelector(':scope > title')) return el; el = el.parentNode; } return null; } function place(x, y) { // Ustawiamy najpierw, potem mierzymy — inaczej nie znamy rozmiaru dymka. tip.style.left = '0px'; tip.style.top = '0px'; var w = tip.offsetWidth, h = tip.offsetHeight; var left = x + OFFSET, top = y + OFFSET; if (left + w > window.innerWidth - 4) left = x - OFFSET - w; // odbij w lewo if (top + h > window.innerHeight - 4) top = y - OFFSET - h; // odbij w górę tip.style.left = Math.max(4, left) + 'px'; tip.style.top = Math.max(4, top) + 'px'; } Array.prototype.forEach.call(wheels, function (svg) { svg.addEventListener('mousemove', function (e) { var el = owner(e.target, svg); if (!el) { hide(); return; } if (!stash || stash.owner !== el) { restore(); var node = el.querySelector(':scope > title'); tip.textContent = node.textContent; stash = { owner: el, node: node }; el.removeChild(node); tip.hidden = false; } place(e.clientX, e.clientY); }); svg.addEventListener('mouseleave', hide); }); // Dymek nie może przeżyć przewinięcia ani powiększenia — zostałby wiszący // w miejscu, w którym nic już nie ma. window.addEventListener('scroll', hide, true); window.addEventListener('resize', hide); document.addEventListener('click', hide, true); }); })();