95a26c9ef09eae3c8d6290eb92712a4c7f31d9c6
hiram
Tue Nov 24 12:20:03 2020 -0800
prepare for future with different track types and different item data structures refs #21980
diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index 8649bca..e02fe81 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -4452,77 +4452,78 @@
"hgTracks?db="+getDb()+"&"+newDbPos+"&hgsid="+sid);
} else {
// Should be when advancing (not-back-button)
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: {},
+ 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
jsonUrl: {}, // list of json files from hidden DIV elements
- maximumWidth: {},
+ 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 if working with delay timer done
- mostRecentMouseEvt: null,
- browserTextSize: 12,
+ delayInProgress: false, // true while waiting for delay timer
+ mostRecentMouseEvt: null, // to use when mouse delay is finished
+ browserTextSize: 12, // default if not found otherwise
- // spans{} - key name is track name, value is an array of
+ // 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 boxes (for debugging)
+ // value is the number of items (for debugging)
// maximumWidth{} - key is track name, value is length of longest
// number string as measured when rendered
// given hgt_....png file name, change to hgt_....json file name
jsonFileName: function(imgDataId)
{
var jsonFile=imgDataId.src.replace(".png", ".json");
return jsonFile;
},
// called from: updateImgForId when it has updated a track in place
// need to refresh the event handlers and json data
updateMouseOver: function (trackName, trackDb)
{
var trackType = null;
var hasChildren = null;
if (trackDb) {
trackType = trackDb.type;
hasChildren = trackDb.hasChildren;
- } else {
- if (hgTracks.trackDb) {
- if (hgTracks.trackDb[trackName]) {
+ } else if (hgTracks.trackDb && hgTracks.trackDb[trackName]) {
trackType = hgTracks.trackDb[trackName].type;
- }
- }
+ } else if (mouseOver.trackType[trackName]) {
+ trackType = mouseOver.trackType[trackName];
}
var tdData = "td_data_" + trackName;
var tdDataId = document.getElementById(tdData);
var imgData = "img_data_" + trackName;
var imgDataId = document.getElementById(imgData);
if (imgDataId && tdDataId) {
var url = mouseOver.jsonFileName(imgDataId);
if (mouseOver.tracks[trackName]) { // > 0 -> seen before in receiveData
$( tdDataId ).mousemove(mouseOver.mouseMoveDelay);
$( tdDataId ).mouseout(mouseOver.popUpDisappear);
mouseOver.fetchJsonData(url); // may be a refresh, don't know
} else {
if (trackType) {
var validType = false;
if (trackType.indexOf("wig") === 0) { validType = true; }
@@ -4532,30 +4533,34 @@
if (validType) {
$( tdDataId ).mousemove(mouseOver.mouseMoveDelay);
$( tdDataId ).mouseout(mouseOver.popUpDisappear);
mouseOver.fetchJsonData(url);
}
}
}
}
},
// 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
// if we knew the array was sorted on x1 we could get out early
// when x < x1
+ // Note, different track types could have different intersection
+ // procedures. For example, the HiC track will need to intersect
+ // the mouse position within the diamond/square defined by the
+ // items in the display.
findRange: function (x, rects)
{
var answer = -1; // assmume not found
var idx = 0;
if (hgTracks.revCmplDisp) {
var rectsLen = rects.length - 1;
for ( idx in rects ) {
if ((rects[rectsLen-idx].x1 <= x) && (x < rects[rectsLen-idx].x2)) {
answer = rectsLen-idx;
break;
}
}
} else {
for ( idx in rects ) {
if ((rects[idx].x1 <= x) && (x < rects[idx].x2)) {
@@ -4607,51 +4612,51 @@
// var evtY = Math.floor(evt.pageY);
// var offX = Math.floor(evt.offsetX); // no need for evtY or offX
// find location of this
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 tdWidth = Math.floor(tdRect.width);
var tdHeight = Math.floor(tdRect.height);
var rightSide = tdLeft + tdWidth;
// clientX is the X coordinate of the mouse hot spot
var clientX = Math.floor(evt.clientX);
- // the graphOffset is the index (x coordinate) into the 'spans' definitions
+ // the graphOffset is the index (x coordinate) into the 'items' definitions
// 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, rightSide - clientX);
}
var windowUp = false; // see if window is supposed to become visible
var foundIdx = -1;
- if (mouseOver.spans[trackName]) {
- foundIdx = mouseOver.findRange(graphOffset, mouseOver.spans[trackName]);
+ if (mouseOver.items[trackName]) {
+ foundIdx = mouseOver.findRange(graphOffset, mouseOver.items[trackName]);
}
// can show 'no data' when not found
var mouseOverValue = "no data";
if (foundIdx > -1) { // value to display
- if (mouseOver.spans[trackName][foundIdx].c > 1) {
- mouseOverValue = " μ " + mouseOver.spans[trackName][foundIdx].v + " ";
+ if (mouseOver.items[trackName][foundIdx].c > 1) {
+ mouseOverValue = " μ " + mouseOver.items[trackName][foundIdx].v + " ";
} else {
- mouseOverValue = " " + mouseOver.spans[trackName][foundIdx].v + " ";
+ 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);
var lineTop = Math.max(0, tdTop + msgHeight);
var msgLeft = Math.max(0, clientX - (msgWidth/2) - 3); // with magic 3
var lineLeft = Math.max(0, clientX - 3); // with magic 3
$('#mouseOverText').css('fontSize',mouseOver.browserTextSize);
$('#mouseOverText').css('left',msgLeft + "px");
$('#mouseOverText').css('top',tdTop + "px");
$('#mouseOverVerticalLine').css('left',lineLeft + "px");
$('#mouseOverVerticalLine').css('top',lineTop + "px");
@@ -4705,62 +4710,68 @@
// =======================================================================
// 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.
+ // 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.visible = false;
for (var trackName in arr) {
// clear these variables if they existed before
- if (mouseOver.spans[trackName]) {mouseOver.spans[trackName] = undefined;}
+ 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.spans[trackName] = []; // start array
+ mouseOver.items[trackName] = []; // start array
+ mouseOver.trackType[trackName] = arr[trackName].t;
// 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.spans[trackName][] array
+ // save incoming x1,x2,v data into the mouseOver.items[trackName][] array
var lengthLongestNumberString = 0;
var longestNumber = 0;
var hasMean = false;
- for (var span in arr[trackName]) {
- if (arr[trackName][span].c > 1) { hasMean = true; }
- var lenV = arr[trackName][span].v.toString().length;
+ for (var datum in arr[trackName].d) { // .d is the data array
+ if (arr[trackName].d[datum].c > 1) { hasMean = true; }
+ var lenV = arr[trackName].d[datum].v.toString().length;
if (lenV > lengthLongestNumberString) {
lengthLongestNumberString = lenV;
- longestNumber = arr[trackName][span].v;
+ longestNumber = arr[trackName].d[datum].v;
}
- mouseOver.spans[trackName].push(arr[trackName][span]);
+ mouseOver.items[trackName].push(arr[trackName].d[datum]);
++itemCount;
}
mouseOver.tracks[trackName] = itemCount; // != 0 -> indicates valid track
var mouseOverValue = "";
if (hasMean) {
mouseOverValue = " μ " + longestNumber + " ";
} else {
mouseOverValue = " " + longestNumber + " ";
}
$('#mouseOverText').html(mouseOverValue); // see how big as rendered
$('#mouseOverText').css('fontSize',mouseOver.browserTextSize);
var maximumWidth = Math.ceil($('#mouseOverText').width());
$('#mouseOverText').html("no data"); // might be bigger
if (Math.ceil($('#mouseOverText').width() > maximumWidth)) {
maximumWidth = Math.ceil($('#mouseOverText').width());
|