915f56e3f34f66d58bf6573dc4dfddd068bd4090
angie
Tue Apr 19 13:36:48 2016 -0700
Simplify the generation of hgGateway's dbDbTaxonomy tree info and support mirrors better: new hg.conf setting hgGateway.dbDbTaxonomy enables tree display and specifies relative URL to file. Instead of dbDbTaxonomy.{hgwdev,rr}.js, there is only one dbDbTaxonomy.js, built from hgcentraltest (hgwdev). hgGateway.c's HTML output includes JS encoding the set of active genomes+taxIds. hgGateway.js uses that to prune the tree so it contains only active genomes; now we can use the hgwdev tree on the RR and see only RR species. Also updated dbDbTaxonomy.js to get the latest hgwdev species as of 4/18/16.
refs #15277
diff --git src/hg/js/hgGateway.js src/hg/js/hgGateway.js
index 158f237..24a851f 100644
--- src/hg/js/hgGateway.js
+++ src/hg/js/hgGateway.js
@@ -13,31 +13,32 @@
// hg/hgGateway/hgGateway.html.
// rainbow: module that exports draw() function and colors. draw() adds stripes using
// a spectrum of colors that are associated to species groups. The hgGateway view code
// uses coordinates of stripes within the tree image to create a corresponding "rainbow"
// slider bar to the left of the phylogenetic tree container.
// autocompleteCat: customized JQuery autocomplete plugin that includes watermark and
// can display results broken down by category (for example, genomes from various
// assembly hubs and native genomes).
// hgGateway: module of mostly view/controller code (model state comes directly from server).
// Globals:
/* globals calculateHgTracksWidth */ // pragma for jshint; function is defined in utils.js
-var dbDbTree = dbDbTree || ['dbDbTree is missing!', []];
+var dbDbTree = dbDbTree || undefined;
+var activeGenomes = activeGenomes || undefined;
var cart = cart || undefined;
function svgCreateEl(type, config) {
// Helper function for creating a new SVG element and initializing its
// properties and attributes. Type is something like 'rect', 'text', 'g', etc;
// config is an object like { id: 'newThingie', x: 0, y: 10, title: 'blah blah' }.
var svgns = 'http://www.w3.org/2000/svg';
var xlinkns = 'http://www.w3.org/1999/xlink';
var el = document.createElementNS(svgns, type);
var title, titleEl;
if (el) {
_.forEach(config, function(value, setting) {
if (setting === 'textContent') {
// Text content (the text in a text element or title element) is a property:
el.textContent = value;
@@ -793,30 +794,33 @@
$('.jwIconSprite' + name).parent().children().click(onClick);
}
}
function addCategory(cat, item) {
// Clone item, add category: cat to it and return it (helper function, see below).
var clone = {};
_.assign(clone, item, { category: cat });
return clone;
}
function autocompleteFromTree(node) {
// Traverse dbDbTree to make autocomplete result lists for all non-leaf node labels.
// Returns an object mapping each label of node and descendants to a list of
// result objects with the same structure that we'd get from a server request.
+ if (! node) {
+ return;
+ }
var searchObj = {};
var myResults = [];
var label = node[0], taxId = node[1], kids = node[3];
var addMyLabel;
if (!kids || kids.length === 0) {
// leaf node: return autocomplete result for species
myResults = [ { genome: label,
label: label,
taxId: taxId } ];
} else {
// Accumulate the list of all children's result lists;
// keep each's child searchObj mappings unless the child is a leaf
// (which would be redundant with server autocomplete results).
addMyLabel = addCategory.bind(null, label);
myResults = _.flatten(
@@ -965,31 +969,30 @@
normalizedTop = imageTop / svgHeight;
moveSlider(normalizedTop);
};
// This might be called before the species image has been created; if so, do nothing.
if (! $speciesTree || speciesTree.length === 0) {
return;
}
makeRainbowSliderStripes($sliderBar, onClickStripe, svgHeight, stripeColors, stripeTops);
resizeSliderIcon($sliderIcon, svgHeight, sliderBarHeight);
$sliderIcon.draggable({ axis: 'y',
containment: '#speciesGraphic',
drag: onDragSlider
});
- $sliderIcon.show();
$speciesPicker.scroll(onScrollImage);
}
function findScrollbarWidth() {
var widthPlain = $("#sbTestContainerDPlain").width();
var widthInsideScroll = $("#sbTestContainerDInsideScroll").width();
$('#sbTestContainer').hide();
return widthPlain - widthInsideScroll;
}
function setRightColumnWidth() {
// Adjust the width of the "Find Position" section so it fits to the right of the
// "Browse/Select Species" section.
var ieFudge = scrollbarWidth ? scrollbarWidth + 4 : 0;
var extraFudge = 4;
@@ -1041,48 +1044,100 @@
return matches[1];
} else {
return null;
}
}
function highlightLabelForDb(db, taxId) {
var hubName = hubNameFromDb(db);
if (hubName) {
highlightLabel('textEl_' + hubName, true);
} else {
highlightLabel('textEl_' + taxId, true);
}
}
+ function pruneInactive(node, activeGenomes, activeTaxIds) {
+ // Return true if some leaf descendant of node is in activeGenomes or activeTaxIds.
+ // Remove any child that returns false.
+ // If one of {genome, taxId} matches but not the other, tweak the other to match dbDb,
+ // Since we'll be using the hgwdev dbDbTree on the RR which may have been tweaked.
+ var genome = node[0], taxId = node[1], kids = node[3];
+ var hasActiveLeaf = false, i, dbDbTaxId, dbDbGenome;
+ if (!kids || kids.length === 0) {
+ // leaf node: is it active?
+ dbDbTaxId = activeGenomes[genome];
+ if (dbDbTaxId) {
+ hasActiveLeaf = true;
+ node[1] = dbDbTaxId;
+ }
+ // Yet another special case for Baboon having one genome with two species...
+ // maybe we should just change dbDb?
+ else if (_.startsWith(genome, 'Baboon ') && (taxId === 9555 || taxId === 9562)) {
+ hasActiveLeaf = true;
+ } else {
+ dbDbGenome = activeTaxIds[taxId];
+ if (dbDbGenome) {
+ hasActiveLeaf = true;
+ node[0] = dbDbGenome;
+ }
+ }
+ } else {
+ // parent node: splice out any child nodes with no active leaves
+ for (i = kids.length - 1; i >= 0; i--) {
+ if (pruneInactive(kids[i], activeGenomes, activeTaxIds)) {
+ hasActiveLeaf = true;
+ } else {
+ kids.splice(i, 1);
+ }
+ }
+ }
+ return hasActiveLeaf;
+ }
+
function drawSpeciesPicker() {
+ // Prune inactive genomes from dbDbTree.
+ // If dbDbTree is nonempty and SVG is supported, draw the tree; if SVG is not supported,
+ // use the space to suggest that the user install a better browser.
+ // If dbDbTree doesn't exist, leave the "Represented Species" section hidden.
var svg, spTree, stripeTops;
+ var activeTaxIds = _.invert(activeGenomes);
+ if (dbDbTree && pruneInactive(dbDbTree, activeGenomes, activeTaxIds)) {
if (document.createElementNS) {
// Draw the phylogenetic tree and do layout adjustments
svg = document.getElementById('speciesTree');
spTree = speciesTree.draw(svg, dbDbTree, uiState.hubs,
{ onClickSpeciesName: 'hgGateway.onClickSpeciesLabel',
onClickHubName: 'hgGateway.onClickHubName',
hgHubConnectUrl: 'hgHubConnect?hgsid=' + window.hgsid,
containerWidth: $('#speciesPicker').width()
});
setSpeciesPickerSizes(spTree.width, spTree.height);
highlightLabelForDb(uiState.db, uiState.taxId);
- stripeTops = rainbow.draw(svg, dbDbTree, spTree.yTree, spTree.height, spTree.leafTops);
- initRainbowSlider(spTree.height, rainbow.colors, stripeTops);
+ stripeTops = rainbow.draw(svg, dbDbTree,
+ spTree.yTree, spTree.height, spTree.leafTops);
} else {
$('#speciesTreeContainer').html(getBetterBrowserMessage);
}
+ $('#representedSpeciesTitle').show();
+ $('#speciesGraphic').show();
+ if (dbDbTree) {
+ // This needs to be done after things are visible so the slider gets the
+ // right position.
+ initRainbowSlider(spTree.height, rainbow.colors, stripeTops);
+ }
+ }
}
function onSelectGene(item) {
// Set the position from an autocomplete result;
// set hgFindMatches and make sure suggestTrack is in pack mode for highlighting the match.
var newPos = item.id;
var settings;
$('#positionDisplay').text(newPos);
if (uiState.suggestTrack) {
settings = { 'hgFind.matches': item.internalId };
settings[uiState.suggestTrack] = 'pack';
cart.send({ cgiVar: settings });
cart.flush();
}
// Overwrite the selected item w/actual position after the autocomplete plugin is done: