1bad77cde561abffb1db68d686ddd1de11ef8649
hiram
  Fri Oct 30 21:27:35 2020 -0700
correctly handle failedRequest and smaller vertical line however once a track is knocked out it does not come back with zoom in refs #21980

diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index 2e634c7..92e8630 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -4455,30 +4455,31 @@
                 imageV2.history.pushState({lastDbPos: newDbPos, position: newPos, hgsid: + sid },title,
                                  "hgTracks?db="+getDb()+"&"+newDbPos+"&hgsid="+sid);
             }
         }
     }
 };
 
   ///////////////////////////////////////
  //// mouseOver data display 2020-10 ///
 ///////////////////////////////////////
 var mouseOver = {
 
     spans: {},
     visible: false,
     tracks: {},
+//    popUpDelay: 100000,       // can not get this to work ?
 
     // spans{} - key name is track name, value is an array of
     //                   objects: {x1, x2, value}
     // visible - keep track of window visible or not, value: true|false
     //           shouldn't need to do this here, the window knows if it
     //           is visible or not, just ask it for status
     // tracks{}  - tracks that were set up initially, key is track name
     //             value is the number of boxes (for debugging)
 
     // given hgt_....png file name, change to trackName_....json file name
     jsonFileName: function(imgElement, trackName)
     {
       var jsonFile=imgElement.src.replace("hgt/hgt_", "hgt/" + trackName + "_");
       jsonFile = jsonFile.replace(".png", ".json");
       return jsonFile;
@@ -4515,106 +4516,123 @@
            break;
          }
       }
       return answer;
     },
 
     popUpDisappear: function () {
       if (mouseOver.visible) {        // should *NOT* have to keep track !*!
 //       $('#mouseOverText').hide();       // does not function ?
         var msgWindow = document.querySelector(".wigMouseOver");
         msgWindow.classList.toggle("showMouseOver");
         mouseOver.visible = false;
 //        $('#mouseOverContainer').css('display','none'); // does not work
         $('#mouseOverLine').css('display','none');
       }
+//      mouseOver.popUpDelay = 100000;
     },
 
     popUpVisible: function () {
       if (! mouseOver.visible) {        // should *NOT* have to keep track !*!
 //      $('#mouseOverText').show();     // does not function ?
       var msgWindow = document.querySelector(".wigMouseOver");
         msgWindow.classList.toggle("showMouseOver");
         mouseOver.visible = true;
 //        $('#mouseOverContainer').css('display','block');  // does not work
         $('#mouseOverLine').css('display','block');
       }
+//      mouseOver.popUpDelay = 10;
     },
 
     //the evt.target.id is the img_data_<trackName> element of the track graphic
     mouseInTrackImage: function (evt)
     {
     // 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.target.id.includes("img_data_")) { return; }
     var trackName = evt.target.id.replace("img_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 tdName = "td_data_" + trackName;
     var tdId  = document.getElementById(tdName);
     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 imageId = document.getElementById(evt.target.id);
     var imageRect = imageId.getBoundingClientRect();
     var imageLeft = Math.floor(imageRect.left);
     var imageTop = Math.floor(imageRect.top);
-    var imageHeight = Math.floor(imageRect.height);
+//    var imageHeight = Math.floor(imageRect.height);
     var srcUrl = evt.target.src;
     var evX = evt.x;      // location of mouse on the web browser screen
     var evY = evt.y;
     var offLeft = Math.max(0, Math.floor(evt.x - tdLeft));
     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]);
     }
     // might want to indicate 'no data' when not found
     if (foundIdx > -1) {
       // value to display
       var mouseOverValue = "&nbsp;" + mouseOver.spans[trackName][foundIdx].v + "&nbsp;";
       $('#mouseOverText').html(mouseOverValue);
       var msgWidth = Math.ceil($('#mouseOverText').width());
       var msgHeight = Math.ceil($('#mouseOverText').height());
       var posLeft = evt.x - msgWidth + "px";
       var posTop = tdTop + "px";
       $('#mouseOverContainer').css('left',posLeft);
       $('#mouseOverContainer').css('top',posTop);
       $('#mouseOverLine').css('left',evt.x + "px");
       $('#mouseOverLine').css('top',posTop);
       // Setting the height of this line to the full image height eliminates
       //  the mouse event area
-//      $('#mouseOverLine').css('height',imageHeight + "px");
+      $('#mouseOverLine').css('height',tdHeight + "px");
 //      $('#mouseOverLine').height(imageHeight + "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)
 
+/*      this doesn't work, claims there is an error in security policy
+    mouseMoveDelay: function (evt)
+    {
+      if (mouseOver.popUpDelay == 100000) {     // first time here
+        mouseOver.popUpDelay -= 1;              // no longer first time
+        setTimeout(mouseOver.mouseInTrackImage(evt), mouseOver.popUpDelay);
+      } else if (mouseOver.popUpDelay > 10) {
+        return; // wait for first one to complete before issuing more
+      } else {
+        mouseOver.mouseInTrackImage(evt);  // after first one is done, pass them along
+      }
+    },
+*/
+
     // =======================================================================
     // receiveData() callback for successful JSON request, receives incoming
     //             JSON data and gets it into global variables for use here.
     //  The incoming 'arr' is a a set of objects where the object key name is
     //      the track name, used here as an array reference: arr[trackName]
     //        (currently only one object per json file, one file for each track,
     //           this may change to have multiple tracks in one json file.)
     //  The value associated with each track name
     //  is an array of span definitions, where each element in the array is a
     //     mapBox definition object:
     //        {x1:n, x2:n, value:s}
     //        where n is an integer in the range: 0..width,
     //        and s is the value string to display
     //     Will need to get them sorted on x1 for efficient searching as
     //     they accumulate in the local data structure here.
@@ -4650,31 +4668,31 @@
       }
     },
 
     // =========================================================================
     // fetchMapData() sends JSON request, callback to receiveData() upon return
     // =========================================================================
     fetchMapData: function (url, trackName)
     {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.onreadystatechange = function() {
        if (4 === this.readyState && 200 === this.status) {
           var mapData = JSON.parse(this.responseText);
           mouseOver.receiveData(mapData);
        } else {
           if (4 === this.readyState && 404 === this.status) {
-             failedRequest(trackName);
+             mouseOver.failedRequest(trackName);
           }
        }
     };
     xmlhttp.open("GET", url, true);
     xmlhttp.send();  // sends request and exits this function
                      // the onreadystatechange callback above will trigger
                      // when the data has safely arrived
     },
 
     getData: function ()
     {	// verify hgTracks and hgTracks.trackDb exist before running wild
       if (typeof(hgTracks) !== "undefined") {
         if (typeof (hgTracks.trackDb) !== "undefined") {
           for (var trackName in hgTracks.trackDb) {
            var rec = hgTracks.trackDb[trackName];