c2e376e7b6d980f41ff903e6374378d668f11770
kate
  Thu Oct 22 14:41:52 2020 -0700
Multi-region features for sparse tracks.  With virt->multi, needs debug. refs #26385

diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index 0635e06..a023cd3 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -176,31 +176,31 @@
                 // overlap with position?
                 //  if intersection, 
                 if (w.winEnd > start && end > w.winStart) {
                     var s = Math.max(start, w.winStart);
                     var e = Math.min(end, w.winEnd);
                     var cs = s - w.winStart + w.virtStart;
                     var ce = e - w.winStart + w.virtStart;
                     if (newStart === -1)
                         newStart = cs;
                     newEnd = ce;
                 }
                 lastW = w;
             }
         }
         //  return new virt undisguised position as a string
-        var newPos = "virt:" + (newStart+1) + "-" + newEnd;
+        var newPos = "multi:" + (newStart+1) + "-" + newEnd;
         return newPos;
     },
 
     disguiseSize: function(position) // DISGUISE VMODE
     {   // find the real size of the windows spanned
         //  position should be a real chrom span
         var pos = parsePosition(position);
         if (!pos)
             return 0;
         var start = pos.start - 1;
         var end = pos.end;
         var newSize = 0;
         var windows = null;
         for (j=0; j < 3; ++j) {
             if (j === 0) windows = hgTracks.windowsBefore;
@@ -268,59 +268,60 @@
     },
 
     set: function (position, size)
     {   // Set value of position and size (in hiddens and input elements).
         // We assume size has already been commified.
         // Either position or size may be null.
 
         // stack dump  // DEBUG
         //console.trace();
         // NOT work on safari
         //var obj = {};
         //Error.captureStackTrace(obj);
         //warn("genomePos.set() called "+obj.stack);
 
         position = position.replace(/,/g, ""); // strip out any commas
+        position.replace("virt:", "multi:");
 
         if (position) {
             // DISGUISE VMODE
             //warn("genomePos.set() called, position = "+position);
-            if (hgTracks.virtualSingleChrom && (position.search("virt:")===0)) {
+            if (hgTracks.virtualSingleChrom && (position.search("multi:")===0)) {
                 var newPosition = genomePos.disguisePosition(position);
                 //warn("genomePos.set() position = "+position+", newPosition = "+newPosition);
                 position = newPosition;
             }
         }
         if (position) {
             // There are multiple tags with name === "position"
             // (one in TrackHeaderForm and another in TrackForm).
             var tags = document.getElementsByName("position");
             for (var i = 0; i < tags.length; i++) {
                 var ele = tags[i];
                 ele.value = position;
             }
         }
         var pos = parsePosition(position);
         if ($('#positionDisplay').length) {
             // add commas to positionDisplay
             var commaPosition = position;
             if (pos)
                 commaPosition = pos.chrom+":"+commify(pos.start)+"-"+commify(pos.end);  
             $('#positionDisplay').text(commaPosition);
         }
         if (size) {
-            if (hgTracks.virtualSingleChrom && (position.search("virt:")!==0)) {
+            if (hgTracks.virtualSingleChrom && (position.search("multi:")!==0)) {
                 var newSize = genomePos.disguiseSize(position);
                 //warn("genomePos.set() position = "+position+", newSize = "+newSize);
                 if (newSize > 0)
                     size = newSize;
             }
             $('#size').text(commify(size)); // add commas
         }
         if (pos) {
             // fixup external static links on page'
 
             // Example ensembl link:
             // http://www.ensembl.org/Homo_sapiens/contigview?chr=21&start=33031934&end=33041241
             genomePos.linkFixup(pos, "ensemblLink", new RegExp("(.+start=)[0-9]+"), "end");
 
             // Example NCBI Map Viewer link (obsolete):
@@ -544,43 +545,44 @@
                 url: "../cgi-bin/hgTracks",
                 data: cart.varsToUrlData({ 'hgt.convertChromToVirtChrom': pos, 'hgt.trackImgOnly' : 1, 'hgsid': getHgsid() }),
                 dataType: "html",
                 trueSuccess: genomePos.handleConvertChromPosToVirtCoords,
                 success: catchErrorOrDispatch,
                 error: errorHandler,
                 cache: false
             });
         return genomePos.convertedVirtCoords;
     },
 
     positionDisplayDialog: function ()
     // Show the virtual and real positions of the windows
     {   
         var position = genomePos.get();
+        position.replace("virt:", "multi:");
         var positionDialog = $("#positionDialog")[0];
         if (!positionDialog) {
             $("body").append("<div id='positionDialog'><span id='positionDisplayPosition'></span>");
             positionDialog = $("#positionDialog")[0];
         }
         if (hgTracks.windows) {
             var i, len, end;
-            var matches = /^virt:[0-9]+-([0-9]+)/.exec(position);
+            var matches = /^multi:[0-9]+-([0-9]+)/.exec(position);
             var str = position;
             if (matches) {
                 end = matches[1];
                 if (end < hgTracks.chromEnd) {
-                    str += "<br>(full virtual region is virt:1-" + hgTracks.chromEnd + ")";
+                    str += "<br>(full virtual region is multi:1-" + hgTracks.chromEnd + ")";
                 }
             }
             if (!(hgTracks.virtualSingleChrom && (hgTracks.windows.length === 1))) {
                 str += "<br>\n";
                 str += "<br>\n";
                 str += "<ul style='list-style-type:none; max-height:200px; padding:0; width:80%; overflow:hidden; overflow-y:scroll;'>\n";
                 for (i=0,len=hgTracks.windows.length; i < len; ++i) {
                     var w = hgTracks.windows[i];
                     str += "<li>" + w.chromName + ":" + (w.winStart+1) + "-" + w.winEnd +
                                 "&nbsp;&nbsp;&nbsp;" + (w.winEnd - w.winStart) + " bp" + "</li>\n";
                 }
                 str += "</ul>\n";
             }
             $("#positionDisplayPosition").html(str);
         } else {
@@ -1040,30 +1042,31 @@
                     continue; // ignore invalid position strings
                 pos.start--;
 
                 if (pos.chrom === hgTracks.chromName && pos.db === currDb
                 &&  pos.start <= findPos.chromStart && pos.end >= findPos.chromEnd) {
                     return i;
                 }
             }
         }
         return null;
     },
 
     highlightThisRegion: function(newPosition, doAdd, hlColor)
     // set highlighting newPosition in server-side cart and apply the highlighting in local UI.
     {
+        newPosition.replace("virt:", "multi:");
         var hlColorName = hlColor; // js convention: do not assign to argument variables
         if (hlColor==="" || hlColor===null || hlColor===undefined)
             hlColorName = dragSelect.hlColor;
 
         var pos = parsePosition(newPosition);
         var start = pos.start;
         var end = pos.end;
         var newHighlight = makeHighlightString(getDb(), pos.chrom, start, end, hlColorName);
         newHighlight = imageV2.disguiseHighlight(newHighlight);
         var oldHighlight = hgTracks.highlight;
         if (oldHighlight===undefined || doAdd===undefined || doAdd===false || oldHighlight==="") {
             // just set/overwrite the old highlight position, this used to be the default
             hgTracks.highlight = newHighlight;
         }
         else {
@@ -1100,30 +1103,31 @@
                 }
             }
             if (nonVirtChrom !== "")
                 cartSettings.nonVirtHighlight = makeHighlightString(getDb(), nonVirtChrom, nonVirtStart, (nonVirtEnd+1), hlColorName);
         } else if (hgTracks.windows && hgTracks.virtualSingleChrom) {
                 cartSettings.nonVirtHighlight = hgTracks.highlight;
         }
         // TODO if not virt, do we need to erase cart nonVirtHighlight ?
         cart.setVarsObj(cartSettings);
         imageV2.highlightRegion();
     },
 
     selectionEndDialog: function (newPosition)
     // Let user choose between zoom-in and highlighting.
     {   
+        newPosition.replace("virt:", "multi:");
         // if the user hit Escape just before, do not show this dialo
         if (dragSelect.startTime===null)
             return;
         var dragSelectDialog = $("#dragSelectDialog")[0];
         if (!dragSelectDialog) {
             $("body").append("<div id='dragSelectDialog'>" + 
                              "<p><ul>"+
                              "<li>Hold <b>Shift+drag</b> to show this dialog" +
                              "<li>Hold <b>Alt+drag</b> to add a highlight" +
                              "<li>Hold <b>Ctrl+drag</b> (Windows) or <b>Cmd+drag</b> (Mac) to zoom" +
                              "<li>To cancel, press <tt>Esc</tt> anytime or drag mouse outside image" +
                              "<li>Highlight the current position with <tt>h then m</tt>" +
                              "<li>Clear all highlights with View - Clear Highlights or <tt>h then c</tt>" +
                              "</ul></p>" +
                              "<p>Highlight color: <input type='text' style='width:70px' id='hlColorInput' value='"+dragSelect.hlColor+"'>" +
@@ -1155,31 +1159,31 @@
                 showPalette: true,
                 showInput: true,
                 preferredFormat: "hex",
                 change: function() { var color = $("#hlColorPicker").spectrum("get"); $('#hlColorInput').val(color); },
                 };
             $("#hlColorPicker").spectrum(opt);
             // update the color picker if you change the input box
             $("#hlColorInput").change(function(){ $("#hlColorPicker").spectrum("set", $('#hlColorInput').val()); });
         }
 
         $("#hlColorPicker").spectrum("set", $('#hlColorInput').val());
 
         if (hgTracks.windows) {
             var i,len;
             var newerPosition = newPosition;
-            if (hgTracks.virtualSingleChrom && (newPosition.search("virt:")===0)) {
+            if (hgTracks.virtualSingleChrom && (newPosition.search("multi:")===0)) {
                 newerPosition = genomePos.disguisePosition(newPosition);
             }
             var str = newerPosition + "<br>\n";
             var str2 = "<br>\n";
             str2 += "<ul style='list-style-type:none; max-height:200px; padding:0; width:80%; overflow:hidden; overflow-y:scroll;'>\n";
             var pos = parsePosition(newPosition);
             var start = pos.start - 1;
             var end = pos.end;
             var selectedRegions = 0;
             for (i=0,len=hgTracks.windows.length; i < len; ++i) {
                 var w = hgTracks.windows[i];
                 // overlap with new position?
                 if (w.virtEnd > start && end > w.virtStart) {
                     var s = Math.max(start, w.virtStart);
                     var e = Math.min(end, w.virtEnd);
@@ -1200,31 +1204,31 @@
         $(dragSelectDialog).dialog({
                 modal: true,
                 title: "Drag-and-select",
                 closeOnEscape: true,
                 resizable: false,
                 autoOpen: false,
                 revertToOriginalPos: true,
                 minWidth: 500,
                 buttons: {  
                     "Zoom In": function() {
                         // Zoom to selection
                         $(this).dialog("option", "revertToOriginalPos", false);
                         if ($("#disableDragHighlight").attr('checked'))
                             hgTracks.enableHighlightingDialog = false;
                         if (imageV2.inPlaceUpdate) {
-                            if (hgTracks.virtualSingleChrom && (newPosition.search("virt:")===0)) {
+                            if (hgTracks.virtualSingleChrom && (newPosition.search("multi:")===0)) {
                                 newPosition = genomePos.disguisePosition(newPosition); // DISGUISE
                             }
                             var params = "position=" + newPosition;
                             if (!hgTracks.enableHighlightingDialog)
                                 params += "&enableHighlightingDialog=0";
                             imageV2.navigateInPlace(params, null, true);
                         } else {
                             $('body').css('cursor', 'wait');
                             if (!hgTracks.enableHighlightingDialog)
                                 cart.setVarsObj({'enableHighlightingDialog': 0 },null,false); // async=false
                             document.TrackHeaderForm.submit();
                         }
                         $(this).dialog("close");
                     },
                     "Single Highlight": function() {
@@ -1289,44 +1293,45 @@
             return false;
         // ignore releases outside of the image rectangle (allowing a 10 pixel slop)
         if (genomePos.check(img, selection)) {
             // ignore single clicks that aren't in the top of the image
             // (this happens b/c the clickClipHeight test in dragSelect.selectStart
             // doesn't occur when the user single clicks).
             doIt = (dragSelect.startTime !== null || rulerClicked);
         }
 
         if (doIt) {
             // dragSelect.startTime is null if mouse has never been moved
             var singleClick = (  (selection.x2 === selection.x1)
                               || dragSelect.startTime === null
                               || (now.getTime() - dragSelect.startTime) < 100);
             var newPosition = genomePos.update(img, selection, singleClick);
+            newPosition.replace("virt:", "multi:");
             if (newPosition) {
                 if (event.altKey) {
                     // with the alt-key, only highlight the region, do not zoom
                     dragSelect.highlightThisRegion(newPosition, true);
                     $(imageV2.imgTbl).imgAreaSelect({hide:true});
                 } else {
                     if (hgTracks.enableHighlightingDialog && !(event.metaKey || event.ctrlKey))
                         // don't show the dialog if: clicked on ruler, if dialog deactivated or meta/ctrl was pressed
                         dragSelect.selectionEndDialog(newPosition);
                     else {
                         // in every other case, show the dialog
                         $(imageV2.imgTbl).imgAreaSelect({hide:true});
                         if (imageV2.inPlaceUpdate) {
-                            if (hgTracks.virtualSingleChrom && (newPosition.search("virt:")===0)) {
+                            if (hgTracks.virtualSingleChrom && (newPosition.search("multi:")===0)) {
                                 newPosition = genomePos.disguisePosition(newPosition); // DISGUISE
                             }
                             imageV2.navigateInPlace("position=" + newPosition, null, true);
                         } else {
                             jQuery('body').css('cursor', 'wait');
                             document.TrackHeaderForm.submit();
                         }
                     }
                 }
             } else {
                 $(imageV2.imgTbl).imgAreaSelect({hide:true});
                 genomePos.revertToOriginalPos();
             }
             dragSelect.startTime = null;
             // blockMapClicks/allowMapClicks() is necessary if selectEnd was over a map item.
@@ -3334,35 +3339,36 @@
     } else if (hgTracks.windows && hgTracks.nonVirtPosition) {
         position = hgTracks.nonVirtPosition;
     }
     var pos = parsePosition(position);
     if (pos) {
         var url = "hgc?hgsid="+getHgsid()+"&g=getDna&i=mixed&c="+pos.chrom+"&l="+pos.start+"&r="+pos.end+"&db="+getDb();
         window.location.href = url;
     }
     return false;
 }
 
 // A function for the keyboard shortcuts "zoom to x bp"
 function zoomTo(zoomSize) {
     var flankSize = Math.floor(zoomSize/2);
     var pos = parsePosition(genomePos.get());
+    pos.replace("virt:", "multi:");
     var mid = pos.start+(Math.floor((pos.end-pos.start)/2));
     var newStart = Math.max(mid - flankSize, 0);
     var newEnd = mid + flankSize - 1;
     var newPos = genomePos.setByCoordinates(pos.chrom, newStart, newEnd);
-    if (hgTracks.virtualSingleChrom && (newPos.search("virt:")===0))
+    if (hgTracks.virtualSingleChrom && (newPos.search("multi:")===0))
         newPos = genomePos.disguisePosition(newPosition); // DISGUISE?
     imageV2.navigateInPlace("position="+newPos, null, true);
 }
 
 // A function for the keyboard shortcuts "highlight add/clear/new"
 function highlightCurrentPosition(mode) {
     var pos = genomePos.get();
     if (mode=="new")
         dragSelect.highlightThisRegion(pos, false);
     else if (mode=="add")
         dragSelect.highlightThisRegion(pos, true);
     else {
         hgTracks.highlight = "";
         var cartSettings = {'highlight': ""};
         cart.setVarsObj(cartSettings);