48a9ad0dffa17597791e51ac5dbaf38eee270864
hiram
  Wed Nov 4 11:18:44 2020 -0800
clean up mouseOver.css and fix off positions in hgTracks refs #21980

diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index 938879f..20e5da7 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -4550,64 +4550,91 @@
     // the center label also events here, can't use that
     //  plus there is a one pixel line under the center label that has no
     //   id name at all, so verify we are getting the event from the correct
     //   element.
     if (! evt.currentTarget.id.includes("td_data_")) { return; }
     var trackName = evt.currentTarget.id.replace("td_data_", "");
     if (trackName.length < 1) { return; }	// verify valid trackName
     // find location of this <td> slice in the image, this is the track
     //   image in the graphic, including left margin and center label
     //   This location follows the window scrolling, could go negative
     var tdId  = document.getElementById(evt.currentTarget.id);
     var tdRect = tdId.getBoundingClientRect();
     var tdLeft = Math.floor(tdRect.left);
     var tdTop = Math.floor(tdRect.top);
     var tdHeight = Math.floor(tdRect.height);
+
     // find the location of the image itself, this could be the single complete
     //  graphic image of all the tracks, or possibly the single image of the
     //  track itself.  This location also follows the window scrolling and can
     //  even go negative when the web browser scrolls a window that is larger
     //  than the width of the web browser.
-    var imageName = "img_data_" + trackName;
-    var imageId = document.getElementById(imageName);
-    var imageRect = imageId.getBoundingClientRect();
-    var imageLeft = Math.floor(imageRect.left);
-    var imageTop = Math.floor(imageRect.top);
-    var evtX = evt.pageX;      // location of mouse on the web browser screen
-    var evtY = evt.pageY;
-    var offLeft = Math.max(0, Math.floor(evtX - tdLeft));
+    var imgName = "img_data_" + trackName;
+    var imgId = document.getElementById(imgName);
+    var imgRect = imgId.getBoundingClientRect();
+    var imgLeft = Math.floor(imgRect.left);
+    var imgTop = Math.floor(imgRect.top);
+    var imgWidth = Math.floor(imgRect.width);
+    var imgHeight = Math.floor(imgRect.height);
+    var imgRectX = Math.floor(imgRect.x);
+    var evtX = Math.floor(evt.pageX);      // location of mouse relative to the whole page
+    var evtY = Math.floor(evt.pageY);      // even when the top of page has scolled off
+    var offX = Math.floor(evt.offsetX);
+    // This is very strange how this offLeft worked out, but it does work.
+    //   What offLeft measures is how far into the graph is the cursor from
+    //     the left side of the graph.  This is needed as an index to find
+    //     the data values that belong to the graph which are in mouseOver.spans
+    //     It is always a positive number from 0 to (N-1) where N is the
+    //       number of pixels in the graph.
+    //  The jQuery pageX,pageY are a bit odd, they are always positive as
+    //      measured from the top left corner of the page.  The 'page' is
+    //      the whole document even when it scrolls off screen to the top.
+    //      jQuery documentation says the evt.offsetX is not always supported
+    //      by all browsers.  Will see about that.
+    //  I don't see a way to simplify this offLeft.  What I'm seeing is that
+    //      evtX-offsetX is always 3, which I believe is the margin on the left
+    //      side of the page between the page edge and where the image begins.
+    //      Then, tdLeft is the offset from the left edge of the image to where
+    //      the graph begins.  This tdLeft changes as the window scrolls left
+    //      and right, including going negative when it scrolls off screen left.
+    //
+    var offLeft = Math.max(0, Math.floor(2*offX - tdLeft + imgRectX - evtX));
     var windowUp = false;     // see if window is supposed to become visible
     var foundIdx = -1;
     if (mouseOver.spans[trackName]) {
        foundIdx = mouseOver.findRange(offLeft, mouseOver.spans[trackName]);
     }
-    // TBD: will want to indicate 'no data' when not found
+    // can show 'no data' when not found
     if (foundIdx > -1) {
       // value to display
-      var mouseOverValue = "&nbsp;" + mouseOver.spans[trackName][foundIdx].v + "&nbsp;";
+      mouseOverValue = "&nbsp;" + mouseOver.spans[trackName][foundIdx].v + "&nbsp;";
+      $('#mouseOverText').html(mouseOverValue);
+    } else {
+      var mouseOverValue = "no data";
       $('#mouseOverText').html(mouseOverValue);
+    }
     var msgWidth = Math.ceil($('#mouseOverText').width());
     var msgHeight = Math.ceil($('#mouseOverText').height());
-      var posLeft = evtX - msgWidth + "px";
+    var posLeft = imgLeft + offX - msgWidth + "px";
     var posTop = tdTop + "px";
     $('#mouseOverText').css('left',posLeft);
     $('#mouseOverText').css('top',posTop);
-      $('#mouseOverVerticalLine').css('left',evtX + "px");
+    $('#mouseOverVerticalLine').css('left',imgLeft + offX + "px");
     $('#mouseOverVerticalLine').css('top',posTop);
     $('#mouseOverVerticalLine').css('height',tdHeight + "px");
     windowUp = true;      // yes, window is to become visible
-    }
+
     if (windowUp) {     // the window should become visible
       mouseOver.popUpVisible();
     } else {    // the window should disappear
       mouseOver.popUpDisappear();
     } //      window visible/not visible
     },  //      mouseInTrackImage function (evt)
 
     // timeout calls here upon completion
     delayCompleted: function()
     {
        mouseOver.delayDone = true;
        // mouse could just be sitting there with no events, if there
        // have been events during the timer, the evt has been recorded
        // so the popUp appears where the mouse is while it moved during the
        // time delay since mostRecentMouseEvt is up to date to now