diff --git a/web/app.js b/web/app.js index 5bf737b..ed7feb8 100644 --- a/web/app.js +++ b/web/app.js @@ -223,20 +223,40 @@ function makeNotePin(note, idx) { c.setAttribute("stroke", "#1a1208"); c.setAttribute("stroke-width", "3"); g.appendChild(c); - const t = document.createElementNS(SVG_NS, "text"); - t.setAttribute("y", 9); - t.setAttribute("font-size", "26"); - t.setAttribute("text-anchor", "middle"); - t.setAttribute("fill", "#1a1208"); - t.setAttribute("font-weight", "900"); - t.setAttribute("font-style", "italic"); - t.setAttribute("font-family", "Georgia, serif"); - t.textContent = "i"; - g.appendChild(t); + const i = document.createElementNS(SVG_NS, "text"); + i.setAttribute("y", 9); + i.setAttribute("font-size", "26"); + i.setAttribute("text-anchor", "middle"); + i.setAttribute("fill", "#1a1208"); + i.setAttribute("font-weight", "900"); + i.setAttribute("font-style", "italic"); + i.setAttribute("font-family", "Georgia, serif"); + i.textContent = "i"; + g.appendChild(i); - const title = document.createElementNS(SVG_NS, "title"); - title.textContent = note.text || "(empty)"; - g.appendChild(title); + // Always-visible label: text rendered next to the pin in image-pixel + // space, with a dark stroke for readability over the parchment. + if (note.text) { + const label = document.createElementNS(SVG_NS, "text"); + label.setAttribute("class", "note-label"); + label.setAttribute("x", 30); // sits to the right of the circle + label.setAttribute("y", 10); + label.setAttribute("font-size", "28"); + label.setAttribute("font-family", "system-ui, sans-serif"); + label.setAttribute("font-weight", "600"); + label.setAttribute("fill", "#fff7d6"); + label.setAttribute("stroke", "#1a1208"); + label.setAttribute("stroke-width", "5"); + label.setAttribute("paint-order", "stroke"); + // Truncate very long text on the SVG side to ~80 chars so it doesn't + // overflow the map. The full text is still in the data tooltip. + const truncated = note.text.length > 80 ? note.text.slice(0, 77) + "..." : note.text; + label.textContent = truncated; + g.appendChild(label); + } + + // Custom-tooltip data (instant, used by ensureTooltip). + g.dataset.tooltip = note.text || "(empty)"; // drag-to-move + right-click delete + double-click to edit text g.addEventListener("pointerdown", (e) => { @@ -325,10 +345,8 @@ function makeEnemyPin(e) { t.textContent = "☠"; g.appendChild(t); } - const title = document.createElementNS(SVG_NS, "title"); const tag = cls === 5 ? " (rare)" : (e.skippable ? " (skippable)" : ""); - title.textContent = e.name + tag; - g.appendChild(title); + g.dataset.tooltip = e.name + tag; return g; } @@ -361,9 +379,9 @@ function makeIconMarker(ic) { g.appendChild(r); } if (ic.comment) { - const title = document.createElementNS(SVG_NS, "title"); - title.textContent = ic.comment; - g.appendChild(title); + g.dataset.tooltip = ic.comment; + } else if (ic.type) { + g.dataset.tooltip = ic.type; } return g; } @@ -559,6 +577,60 @@ function zoomBy(factor, anchorX, anchorY) { applyView(); } +/* --- instant tooltip ------------------------------------------------------ + * SVG