5e55b76e29e2ac663dcfa4e288bd0caa701ab3da
hiram
  Mon May 3 13:36:12 2021 -0700
adding mouseOverFunction trackDb variable and feature to turn off mouse over value display for averaged values refs #27457

diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index e886be7..70de7d1 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -4517,41 +4517,43 @@
                                  "hgTracks?db="+getDb()+"&"+newDbPos+"&hgsid="+sid);
             }
         }
     }
 };
 
   ///////////////////////////////////////
  //// mouseOver data display 2020-10 ///
 ///////////////////////////////////////
 var mouseOver = {
 
     items: {},  // items[trackName][] - data for each item in this track
     visible: false,     // keeping track of popUp window visibility
     tracks: {}, // tracks[trackName] - number of data items for this track
     trackType: {},	// key is track name, value is track type from hgTracks
+    mouseOverFunction: {}, // key is track name, value mouseOverFunction string
     jsonUrl: {},       // list of json files from hidden DIV elements
     maximumWidth: {},   // maximumWidth[trackName] - largest string to display
     popUpDelay: 200,   // 0.2 second delay before popUp appears
     popUpTimer: null,// handle from setTimeout to use in clearTimout(popUpTimer)
     delayDone: true,   // mouse has not left element, still receiving move evts
     delayInProgress: false,        // true while waiting for delay timer
     mostRecentMouseEvt: null,   // to use when mouse delay is finished
     browserTextSize: 12,        // default if not found otherwise
     measureTextBox: null,
     noDataString: "no data",	// message for no data at this position
     noDataSize: 0,	// will be set to size of text 'no data'
+    noAverageString: " zoom in to see values ",	// "noAverage" function
 
     // items{} - key name is track name, value is an array of data items
     //           where the format of each item can be different for different
     //           data tracks.  For example, the wiggle track is an array of:
     //                   objects: {x1, x2, v, c}
     //           where [x1..x2) is the array index where the value 'v'
     //           is found, and 'c' is the data value count in this value
     //           i.e. when c > 1 the value is a 'mean' of 'c' data values
     // 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 items (for debugging)
     // maximumWidth{} - key is track name, value is length of longest
     //                  number string as measured when rendered
@@ -4694,30 +4696,33 @@
     //  of the data value boxes for the graph.  The magic number three
     //   is used elsewhere in this code, note the comment on the constant
     //   LEFTADD.
     var graphOffset = Math.max(0, clientX - tdLeft - 3);
     if (hgTracks.revCmplDisp) {
        graphOffset = Math.max(0, tdRight - clientX);
     }
 
     var windowUp = false;     // see if window is supposed to become visible
     var foundIdx = -1;
     if (mouseOver.items[trackName]) {
        foundIdx = mouseOver.findRange(graphOffset, mouseOver.items[trackName]);
     }
     // can show 'no data' when not found
     var mouseOverValue = mouseOver.noDataString;
+    if (mouseOver.mouseOverFunction[trackName] === "noAverage") {
+       mouseOverValue = mouseOver.noAverageString;
+    }
     if (foundIdx > -1) { // value to display
       if (mouseOver.items[trackName][foundIdx].c > 1) {
         mouseOverValue = " ~ " + mouseOver.items[trackName][foundIdx].v + " ";
       } else {
         mouseOverValue = " " + mouseOver.items[trackName][foundIdx].v + " ";
       }
     }
     $('#mouseOverText').html(mouseOverValue);
     var msgWidth = mouseOver.maximumWidth[trackName];
     $('#mouseOverText').width(msgWidth);
     var msgHeight = Math.ceil($('#mouseOverText').height());
     var lineHeight = Math.max(0, tdHeight - msgHeight);
     if (tdTop < 0) {
        lineHeight = Math.max(0, tdHeight + tdTop - msgHeight);
     }
@@ -4818,30 +4823,35 @@
     //  2020-11-24 more generalized incoming data structure, don't care
     //             what the structure is for each item, this will vary
     //             depending upon the type of track.  trackType now remembered
     //             in mouseOver.trackType[trackName]
     // =======================================================================
     receiveData: function (arr)
     {
       mouseOver.popUpDisappear();
       for (var trackName in arr) {
 	// clear these variables if they existed before
       if (mouseOver.trackType[trackName]) {mouseOver.trackType[trackName] = undefined;}
       if (mouseOver.items[trackName]) {mouseOver.items[trackName] = undefined;}
       if (mouseOver.tracks[trackName]) {mouseOver.tracks[trackName] = 0;}
       mouseOver.items[trackName] = [];      // start array
       mouseOver.trackType[trackName] = arr[trackName].t;
+      if (arr[trackName].hasOwnProperty('mo')) {
+         mouseOver.mouseOverFunction[trackName] = arr[trackName].mo;
+      } else {
+         delete mouseOver.mouseOverFunction[trackName];
+      }
       // add a 'mousemove' and 'mouseout' event listener to each track
       //     display object
       var tdData = "td_data_" + trackName;
       var tdDataId  = document.getElementById(tdData);
 // from jQuery doc:
 //  As the .mousemove() method is just a shorthand
 //    for .on( "mousemove", handler ), detaching is possible
 //      using .off( "mousemove" ).
       $( tdDataId ).mousemove(mouseOver.mouseMoveDelay);
       $( tdDataId ).mouseout(mouseOver.popUpDisappear);
       var itemCount = 0;	// just for monitoring purposes
       // save incoming x1,x2,v data into the mouseOver.items[trackName][] array
       var lengthLongestNumberString = 0;
       var longestNumber = 0;
       var hasMean = false;
@@ -4850,30 +4860,33 @@
          var lenV = arr[trackName].d[datum].v.toString().length;
          if (lenV > lengthLongestNumberString) {
 	   lengthLongestNumberString = lenV;
 	   longestNumber = arr[trackName].d[datum].v;
          }
         mouseOver.items[trackName].push(arr[trackName].d[datum]);
        ++itemCount;
       }
       mouseOver.tracks[trackName] = itemCount;	// != 0 -> indicates valid track
       var mouseOverValue = "";
       if (hasMean) {
          mouseOverValue = "&nbsp;~&nbsp;" + longestNumber + "&nbsp;";
       } else {
          mouseOverValue = "&nbsp;" + longestNumber + "&nbsp;";
       }
+      if (mouseOver.mouseOverFunction[trackName] === "noAverage") {
+         mouseOverValue = mouseOver.noAverageString;
+      }
       $('#mouseOverText').css('fontSize',mouseOver.browserTextSize);
       var maximumWidth = mouseOver.getWidthOfText(mouseOverValue);
       if ( 0 === mouseOver.noDataSize) {  // only need to do this once
         mouseOver.noDataSize = mouseOver.getWidthOfText(mouseOver.noDataString);
       }
       if (mouseOver.noDataSize > maximumWidth) {
           maximumWidth = mouseOver.noDataSize;
       }
       mouseOver.maximumWidth[trackName] = maximumWidth;
       }
     },  //      receiveData: function (arr)
 
     failedRequest: function(url)
     {   // failed request to get json data, remove it from the URL list
       if (mouseOver.jsonUrl[url]) {