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 + " " + (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);