Skip to content

Commit

Permalink
Make tooltip stay visible and with its text selectable.
Browse files Browse the repository at this point in the history
Instead of creating a tooltip with a <title> svg element (which shows as a tooltip
when the mouse stays for a bit over a box), we now do it with a div, that we
show/hide when appropriate. Its text can be selected, and it looks kind of nice.
  • Loading branch information
jordibc committed Feb 13, 2025
1 parent a0f7ba5 commit da22434
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 14 deletions.
24 changes: 24 additions & 0 deletions ete4/smartview/static/gui.css
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,30 @@
background-color: white;
}

#div_info {
position: absolute;
z-index: 4;
visibility: hidden;
border-style: solid;
border-color: #DDD;
border-width: 2px;
border-radius: 10px;
box-shadow: 3px 3px 3px #DDD;
background-color: white;
padding: 10px;
user-select: text;
}

.info_button {
padding: 3px 8px;
border-style: hidden;
background-color: white;
}

.info_button:hover {
background-color: #EEE;
}

.ctx_button {
width: 100%;
cursor: pointer;
Expand Down
3 changes: 3 additions & 0 deletions ete4/smartview/static/gui.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
<!-- Contains the context menu that appears on mouse right-click -->
<div id="div_contextmenu"></div>

<!-- Contains the "popup" information about the node -->
<div id="div_info"></div>

<!-- Contains the aligned elements (in a rectangular representation) -->
<div id="div_aligned">
<div id="div_aligned_grabber"></div>
Expand Down
30 changes: 16 additions & 14 deletions ete4/smartview/static/js/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,15 +424,28 @@ function create_item(item, tl, zoom, wmax) {

result_of.forEach(t => b.classList.add(get_search_class(t, "results")));

b.addEventListener("click", event =>
b.addEventListener("mousedown", event =>
b.dataset.mousepos = `${event.pageX} ${event.pageY}`);
b.addEventListener("mouseup", event =>
on_box_click(event, box, node_id));
// NOTE: Instead of a "click", we store the position at mousedown (to
// later check if it moved), and trigger the click on the mouseup.

b.addEventListener("contextmenu", event =>
on_box_contextmenu(event, box, name, props, node_id));
b.addEventListener("wheel", event =>
on_box_wheel(event, box), {passive: false});

if (name || Object.entries(props).length > 0)
b.appendChild(create_tooltip(name, props));
// Save information in the box as a data attribute string (.dataset).
if (name || Object.entries(props).length > 0) {
const close = '<button class="info_button" ' +
`onclick="div_info.style.visibility='hidden'">×</button>`;

b.dataset.info = (name ? `<i>${name}</i> ` : "") + close + "<br>" +
(Object.entries(props).map(([k, v]) => `<b>${k}:</b> ${v}`)
.join("<br>"));
// This will be used for the "tooltip" in on_box_click().
}

return b;
}
Expand Down Expand Up @@ -804,17 +817,6 @@ function create_circ_outline(box, tl, z) {
}


// Return an element that, appended to a svg element (normally a box), will
// make it show a tooltip showing nicely the given name and properties.
function create_tooltip(name, props) {
const title = create_svg_element("title", {});
const text = (name ? name : "(unnamed)") + "\n" +
Object.entries(props).map(x => x[0] + ": " + x[1]).join("\n");
title.appendChild(document.createTextNode(text));
return title;
}


function create_line(p1, p2, tl, zx, zy, style="") {
// Transform points to screen coordinates.
const [pt1, pt2] = view.shape === "rectangular" ?
Expand Down
5 changes: 5 additions & 0 deletions ete4/smartview/static/js/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ function on_keydown(event) {
}
else if (key === "Escape") {
div_contextmenu.style.visibility = "hidden";
div_info.style.visibility = "hidden";
}
else {
is_hotkey = false;
Expand Down Expand Up @@ -135,6 +136,10 @@ function on_mousedown(event) {
if (!div_contextmenu.contains(event.target))
div_contextmenu.style.visibility = "hidden";

if (!div_info.contains(event.target) &&
(!div_menu.contains(event.target) && !view.select_text))
div_info.style.visibility = "hidden";

if (event.button && event.button !== 0)
return; // we are only interested in left-clicks

Expand Down
14 changes: 14 additions & 0 deletions ete4/smartview/static/js/gui.js
Original file line number Diff line number Diff line change
Expand Up @@ -711,20 +711,34 @@ function coordinates(point) {


function on_box_click(event, box, node_id) {
if (event.button !== 0)
return; // we are only interested in left-clicks

if (event.detail === 2 || event.ctrlKey) { // double-click or ctrl-click
zoom_into_box(box);
}
else if (event.shiftKey) { // shift-click
view.subtree += (view.subtree ? "," : "") + node_id;
on_tree_change();
}
else { // we simply clicked on this node (maybe show tooltip)
const data = event.target.dataset; // get from data attributes
if (data.mousepos === `${event.pageX} ${event.pageY}`) { // didn't move
div_info.innerHTML = `<p>${data.info}</p>`;
div_info.style.left = `${event.pageX}px`;
div_info.style.top = `${event.pageY}px`;
div_info.style.visibility = "visible"; // show "tooltip"
}
}
}


// Mouse wheel -- zoom in/out (instead of scrolling).
function on_box_wheel(event, box) {
event.preventDefault();

div_info.style.visibility = "hidden"; // in case it was visible

const point = {x: event.pageX, y: event.pageY};
const deltaY = event.deltaY;
const do_zoom = {x: !event.ctrlKey, y: !event.altKey};
Expand Down

0 comments on commit da22434

Please sign in to comment.