0e367d14f1a802e6b644b86f1ea40d48d72c3426
hiram
  Mon Oct 26 12:16:21 2020 -0700
a very dirty version as this changes to more efficient mechanism refs #21980

diff --git src/hg/js/mouseOver.js src/hg/js/mouseOver.js
index 40ca240..3afe19a 100644
--- src/hg/js/mouseOver.js
+++ src/hg/js/mouseOver.js
@@ -1,104 +1,195 @@
 
 // One single top-level object variable to hold all other global variables
 var mapData = {};
 // mapData.rects[] - an array of the rectangles, where each rect is
-//                   {x, y, w, h, v} == x,y width,height, value
+//                   {x1, y1, x2, y2, v} == x1,y1 x2,y2, value
+// mapData.spans{} - key name is track name, value is an array of
+//                   objects: {x1, x2, value}
 // mapData.visible - keep track of window visible or not, value: true|false
-// mapData.tracks[]  - list of tracks with mapBoxes
+//                   shouldn't need to do this here, the window knows if it
+//                   is visible or not, just ask it for status
+// mapData.tracks[]  - list of tracks that came in with mapBoxes
+// mapData.boxCount[]  - in same order as tracks[] number of boxes for track
+//                       this boxCount is just for debugging information
 
 // =========================================================================
-// intersect the point with the rectangle, were rect corners are x1,y1 x2,y2
+// intersect the point with the rectangle, where rect corners are x1,y1 x2,y2
 // =========================================================================
 function intersectPointRectangle(x,y, rect) {
   var answer = true;
   if (x <= rect.x1 || x > rect.x2) { answer = false; }
      else if (y <= rect.y1 || y > rect.y2) { answer = false; }
   return answer;
 }
 
+// given an X coordinate: x, find the index idx
+// in the rects[idx] array where rects[idx].x1 <= x < rects[idx].x2
+// returning -1 when not found
+function findRange(x, rects) {
+  var answer = -1;
+  for ( var idx in rects ) {
+     if ((rects[idx].x1 <= x) && (x < rects[idx].x2)) {
+       answer = idx;
+       break;
+     }
+  }
+  return answer;
+}
+
+function mouseInTrackImage(evt) {
+  var trackName = evt.target.id.replace("img_data_", "");
+  var firstRect = "";
+  if (mapData.spans[trackName]) {
+    var lastRect = mapData.spans[trackName].length - 1;
+    firstRect = mapData.spans[trackName][lastRect].x1 + ".." + mapData.spans[trackName][lastRect].x2;
+  }
+  var evX = evt.x;
+  var evY = evt.y;
+  var oLeft = $(this).offset().left;
+  var oTop = $(this).offset().top;
+  var offLeft = Math.max(0, Math.floor(evt.x - $(this).offset().left));
+  // need to find where offLeft is in the spans
+  var foundIdx = -1;
+  var valP = "noX";
+  if (mapData.spans[trackName]) {
+     foundIdx = findRange(offLeft, mapData.spans[trackName]);
+  }
+  if (foundIdx > -1) { valP = mapData.spans[trackName][foundIdx].v; }
+  var offTop = Math.max(0, Math.floor(evt.y - $(this).offset().top));
+  var msg = "<p>. . . mouse in target.id: " + evt.target.id + "(" + trackName + ")[" + foundIdx + "]='" + valP + "' ["  + firstRect + "] at " + offLeft + "," + offTop + ", evX,Y: " + evX + "," + evY + ", offL,T: " + oLeft + "," + oTop + "</p>";
+  $('#eventRects').html(msg);
+}
+
 // =========================================================================
 // receiveData() callback for successful JSON request, receives incoming JSON
-//             data and gets it into global variables for use here
+//             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 box definitions, where each element in the array is a
+//     mapBox definition object:
+//        {x1:n ,y1:n, x2:n, y2:n, value:s}
+//        where n is an integer in the range: 0..width,
+//        and s is the value string to display
+//  Expecting to simplify this in the next iteration to need only
+//        x1:n, x2:n, value:s
+//     since the y coordinates are found in the DOM object for each track
+//     Will need to get them sorted on x1 for efficient searching as
+//     they accumulate in the local data structure here.
 // =========================================================================
 function receiveData(arr) {
   if (typeof mapData.rects === 'undefined') {
     mapData.rects = [];	// get this array started first time
     mapData.tracks = [];
+    mapData.boxCount = [];
+    mapData.spans = {};
   }
   mapData.visible = false;
-  for (var mapId in arr) {
-    mapData.tracks.push(mapId);
+  for (var trackName in arr) {
+    mapData.tracks.push(trackName);
+    mapData.spans[trackName] = [];
+    // add a 'mousemove' event listener to each track display object
+    var objectName = "td_data_" + trackName;
+    var objectId  = document.getElementById(objectName);
+    objectId.addEventListener('mousemove', mouseInTrackImage);
+    var itemCount = 0;	// just for monitoring purposes
+// got to artifically rewrite the x coordinates going into spans
+    var tdData = "td_data_" + trackName;
+    var tdDataMap = document.getElementById(tdData);
+    var tdRect = tdDataMap.getBoundingClientRect();
+    var xOff = Math.floor(tdRect.left - 71);
     // save all the incoming mapBoxes into the mapData.rects[] array
-    arr[mapId].forEach(function(box) {
-      mapData.rects.push(box)});
+    arr[trackName].forEach(function(box) {
+      var span = { "x1":box.x1-xOff, "x2":box.x2-xOff, "v":box.v };
+      mapData.spans[trackName].push(span);
+      mapData.rects.push(box); ++itemCount});
+    mapData.boxCount.push(itemCount);	// merely for debugging watch
+  }
+  var msg = "<ul>";
+  for (var idx in mapData.tracks) {
+      var trackName = mapData.tracks[idx];
+      var imgData = "td_data_" + trackName;
+      var imgMap  = document.getElementById(imgData);
+      var imageRect = imgMap.getBoundingClientRect();
+      var top = Math.floor(imageRect.top);
+      var left = Math.floor(imageRect.left);
+      var width = Math.floor(imageRect.width);
+      var height = Math.floor(imageRect.height);
+     msg += "<li>" + trackName + " at left,top (x,y)(w,h):" + left + "," + top + "(" + width + "," + height + ") has: " + mapData.boxCount[idx] + " mapBoxes</li>";
   }
+  msg += "</ul>";
+  $('#debugMsg').html(msg);
 }
 
 // =========================================================================
 // fetchMapData() sends JSON request, callback to receiveData() upon return
 // =========================================================================
 function fetchMapData(url) {
   var xmlhttp = new XMLHttpRequest();
   xmlhttp.onreadystatechange = function() {
     if (4 === this.readyState && 200 === this.status) {
       var mapData = JSON.parse(this.responseText);
       receiveData(mapData);
     }
   };
   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
 }	// function fetchMapData()
 
 // Mouse x,y positions arrive as fractions when the
 // WEB page is zoomed into to make the pixels larger.  Hence the Math.floor
 // to keep them as integers.
 function mouseMoving(x, y) {
+  var xyMouse = "<p>. . . mouse at x,y: " + Math.floor(x) + "," + Math.floor(y);
+  $('#xyMouse').html(xyMouse);
   if (typeof mapData.rects !== 'undefined') { // if there are rectangles
     for (var i = 0; i < mapData.tracks.length; i++) {
       var trackName = mapData.tracks[i];
       var imgData = "img_data_" + trackName;
       var imgMap  = document.getElementById(imgData);
       var imageRect = imgMap.getBoundingClientRect();
       var imageTop = imageRect.top;
       // x1,y1 are coordinates of mouse relative to the top,left corner of
       // the browser tracks image
       var x1 = x - Math.floor(imageRect.left);
       var y1 = y - Math.floor(imageRect.top);
       var windowUp = false;     // see if window is supposed to become visible
 
       for (var rect of mapData.rects) {         // work through rects list
         if (intersectPointRectangle(x1,y1, rect)) {     // found mouse in rect
           var msg = "&nbsp;" + rect.v + "&nbsp;";       // value to display
           $('#mouseOverText').html(msg);
           var msgWidth = Math.ceil($('#mouseOverText').width());
           var msgHeight = Math.ceil($('#mouseOverText').height());
           var posLeft = (x - msgWidth) + "px";
           var posTop = (imageTop + rect.y1) + "px";
           $('#mouseOverContainer').css('left',posLeft);
           $('#mouseOverContainer').css('top',posTop);
           windowUp = true;      // yes, window is to become visible
           break;        //      can stop looking after first match
         }
       }
       if (windowUp) {     // the window should become visible
         if (! mapData.visible) {        // should *NOT* have to keep track !*!
           var contain = document.getElementById('mouseOverContainer');
-          var text = document.getElementById('mouseOverText');
-          text.style.backgroundColor = "#ff69b4";
+//          var text = document.getElementById('mouseOverText');
+//          text.style.backgroundColor = "#ff69b4";
           var mouseOver = document.querySelector(".wigMouseOver");
           mouseOver.classList.toggle("showMouseOver");
           mapData.visible = true;
         }
       } else {    // the window should disappear
         if (mapData.visible) {
             var mouseOver = document.querySelector(".wigMouseOver");
             mouseOver.classList.toggle("showMouseOver");
             mapData.visible = false;
         }
       } //      window visible/not visible
     }	//	for each track
   }     //	if there are rectangles defined
 }	//	function mouseMoving(x, y)