From: Chris Jaekl <cejaekl@yahoo.com>
Date: Sat, 11 Nov 2017 06:44:57 +0000 (+0900)
Subject: Adjust tooltip behaviour.
X-Git-Url: https://jaekl.net/gitweb/?a=commitdiff_plain;h=07fb7c12cff3f05994750100aa4b82a24706ac46;p=quanweb.git

Adjust tooltip behaviour.

Adds timeout before display, and centres the tip around the current mouse position.
---

diff --git a/app/index.html b/app/index.html
index 8bd44c4..61f182d 100644
--- a/app/index.html
+++ b/app/index.html
@@ -21,7 +21,7 @@
       Showing <span id="first">0</span> through <span id="last">0</span> out of <span id="count">0</span> matching books.
     </div>
 
-    <div id="books">(No books found)</div>
+    <div id="books" onmousemove="onMouseMove();">(No books found)</div>
 
     <div id="details" class="tooltip" onclick="hideDetails();">(No information available)</div>
 
diff --git a/app/lib.css b/app/lib.css
index 843aded..97d6822 100644
--- a/app/lib.css
+++ b/app/lib.css
@@ -83,7 +83,7 @@ div.tooltip {
   display: none;
   margin: 4px 0px 0px 0px;
   padding: 3px 3px 3px 3px;
-  position: fixed;
+  position: absolute;
   left: 50;
   text-decoration: none;
   top: 50;
diff --git a/app/lib.js b/app/lib.js
index d59c350..0f70f32 100644
--- a/app/lib.js
+++ b/app/lib.js
@@ -4,18 +4,29 @@
 g_state = {
 		cache: [],
 		count: 0,
+		mousePos: {	// Last known position of the mouse cursor
+			x: undefined,
+			y: undefined
+		},
 		first: 0,
 		ids: [],
 		last: (-1),
 		map: {},	// map from book.Id to index into cache[]
-		pageSize: 9,
+		pageSize: 48,
 		tooltip: {
 			bookId: undefined,
 			milliSecs: 500,     // time to wait before displaying tooltip
+			mousePos: {
+				x: undefined,
+				y: undefined
+			},
+			threshold: 10,		// number of pixels that mouse can move before tip is dismissed
 			timer: undefined
 		}
 }
 
+document.onmousemove = onMouseMove;
+
 function adjustPos(setting) {
 	var value = parseInt(setting)
 
@@ -24,7 +35,7 @@ function adjustPos(setting) {
 		return;
 	}
 
-	var maxFirst = g_state.count - g_state.pageSize;
+	var maxFirst = Math.max(0, g_state.count - g_state.pageSize);
 
 	if (value < 0) {
 		g_state.first = 0;
@@ -56,7 +67,6 @@ function bookHtml(book) {
 	}
 	result     +=       '</a></td>'
 		+       '<td onclick="displayDetails(' + book.Id + ');" '
-		+          ' onmouseout="stopTooltipTimer(); hideDetails();" '
 		+          ' onmouseover="startTooltipTimer(' + book.Id + ');">'
 		+         '<p><b>' + book.Title + '</b></p>'
 		+         '<p>'
@@ -113,17 +123,55 @@ function constructSearchUrl() {
 
 // Set the book ID for the details pane, and then show it
 function displayDetails(bookId) {
-	console.log('displayDetails()', bookId);
 	g_state.tooltip.bookId = bookId;
 	showDetails();
 }
 
 function hideDetails() {
+	g_state.tooltip.mousePos.x = undefined;
+	g_state.tooltip.mousePos.y = undefined;
+	
 	var elem = document.getElementById('details');
-	elem.innerHtml = '';
+	elem.innerHTML = '';
 	elem.style.display = 'none';
 }
 
+function onMouseMove(event) {
+	if (typeof event === 'undefined') {
+		return;
+	}
+	
+	var x = event.pageX;
+	var y = event.pageY;
+	
+	if (  x === g_state.mousePos.x
+	   && y === g_state.mousePos.y)
+	{
+		// No change from previous known position. 
+		// Nothing to see (or do) here, move along.
+		return;
+	}
+	
+	// Remember current mouse (x,y) position
+	g_state.mousePos.x = x;
+	g_state.mousePos.y = y;
+
+	// Is there an active tooltip?
+	if (typeof g_state.tooltip.mousePos.x === 'undefined') {
+		// No active tooltip, so nothing further to do
+		return;
+	}
+	
+	var deltaX = Math.abs(x - g_state.tooltip.mousePos.x);
+	var deltaY = Math.abs(y - g_state.tooltip.mousePos.y);
+	
+	if (  deltaX > g_state.tooltip.threshold
+	   || deltaY > g_state.tooltip.threshold )
+	{
+		hideDetails();
+	}
+}
+
 function onNext() {
 	if (g_state.last < (g_state.count - 1)) {
 		adjustPos(g_state.first + g_state.pageSize);
@@ -141,17 +189,12 @@ function onSlide(value) {
 }
 
 function onSearch() {
-	console.log('onSearch()');
-
 	var url = constructSearchUrl();
 
-	report('Loading data from server, please wait...')
-	console.log('Fetching:  "' + url + '"...')
-
 	fetch(url, {method:'GET', cache:'default'})
 	.then(response => response.json())
 	.then((jsonValue) => {
-		console.log('JSON response:  ', jsonValue);
+		// console.log('JSON response:  ', jsonValue);
 		g_state.ids = jsonValue
 		g_state.count = g_state.ids.length;
 		g_state.first = (-1)
@@ -169,8 +212,6 @@ function onSearch() {
 }
 
 function refreshData() {
-	report('Loading details for books ' + g_state.first + ' through ' + g_state.last + ', please wait...');
-
 	var i;
 	var url = '/info/?ids=';
 	g_state.map = {};
@@ -187,7 +228,6 @@ function refreshData() {
 	.then(response => response.json())
 	.then((jsonValue) => {
 		console.log('JSON response for info:  ', jsonValue);
-		report('');
 		g_state.cache = jsonValue;
 		refreshLayout();
 	})
@@ -218,8 +258,6 @@ function report(message) {
 }
 
 function showDetails() {
-	console.log('showDetails()', g_state.tooltip.bookId);
-	
 	var id = g_state.tooltip.bookId;
 	var elem = document.getElementById('details');
 	var index = g_state.map[id];
@@ -229,13 +267,33 @@ function showDetails() {
 	+ ce(book.Description)
 	+ '</div>';
 
+	// Remember the current mouse (x,y).
+	// If we move the mouse too far from this point, that will trigger hiding the tooltip.
+	g_state.tooltip.mousePos.x = g_state.mousePos.x;
+	g_state.tooltip.mousePos.y = g_state.mousePos.y;
+
 	elem.innerHTML = html;
-	elem.style.display = 'block';
+
+	elem.style.display = 'block';	// show, and calculate size, so that we can query it below
+	
+	var x = g_state.mousePos.x;
+	var y = g_state.mousePos.y;
+	
+	var bcr = elem.getBoundingClientRect();
+	
+	var width = bcr.width;
+	var height = bcr.height;
+	
+	x = Math.max(x - (width / 2), 0);
+	y = Math.max(y - (height / 2), 0);
+	
+	elem.style.left = x + 'px';
+	elem.style.top = y + 'px';
 }
 
 function startTooltipTimer(bookId) {
 	if (typeof g_state.tooltip.timer !== 'undefined') {
-		clearTimer(g_state.tooltip.timer);
+		clearTimeout(g_state.tooltip.timer);
 	}
 	g_state.tooltip.bookId = bookId;
 	g_state.tooltip.timer = setTimeout(showDetails, g_state.tooltip.milliSecs);
@@ -245,6 +303,7 @@ function stopTooltipTimer() {
 	if (typeof g_state.tooltip.timer === 'undefined') {
 		return;
 	}
+	
 	clearTimeout(g_state.tooltip.timer);
 	g_state.tooltip.timer = undefined;
 	hideDetails();