773aa9879899908033ea6e64d3344edf069a578e
angie
Wed Apr 20 14:47:01 2016 -0700
Performance improvements: don't do any unnecessary drawing before the first uiState arrives; autocompleteFromTree is actually quite slow so defer it until after the page is displayed.
diff --git src/hg/js/hgGateway.js src/hg/js/hgGateway.js
index 24a851f..3e4181e 100644
--- src/hg/js/hgGateway.js
+++ src/hg/js/hgGateway.js
@@ -790,79 +790,86 @@
// When user clicks on icon, set the taxId (default database);
// scroll the image to that species and clear the species autocomplete input.
onClick = setTaxId.bind(null, taxId, null, true, true);
// Onclick for both the icon and its sibling label:
$('.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) {
+ function autocompleteFromNode(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(
_.map(kids, function(kid) {
var kidLabel = kid[0], kidKids = kid[3];
- var kidObj = autocompleteFromTree(kid);
+ var kidObj = autocompleteFromNode(kid);
// Clone kid's result list and add own label as category:
var kidResults = _.map(kidObj[kidLabel], addMyLabel);
// Add kid's mappings to searchObj only if kid is not a leaf.
if (kidKids && kidKids.length > 0) {
_.assign(searchObj, kidObj);
}
return kidResults;
})
);
}
// Exclude some overly broad categories:
if (label !== 'root' && label !== 'cellular organisms') {
searchObj[label] = myResults;
}
+ return searchObj;
+ }
+
+ function autocompleteFromTree(node, searchObj) {
+ // Traverse dbDbTree to make autocomplete result lists for all non-leaf node labels.
+ // searchObj is extended to map each label of node and descendants to a list of
+ // result objects with the same structure that we'd get from a server request.
+ _.assign(searchObj, autocompleteFromNode(node));
// Add aliases for some common names that map to scientific names in the tree.
_.forEach(commonToSciNames, function(sciName, commonName) {
var label, addMyLabel;
if (searchObj[sciName]) {
label = sciName + ' (' + commonName + ')';
addMyLabel = addCategory.bind(null, label);
searchObj[commonName] = _.map(searchObj[sciName], addMyLabel);
}
});
- return searchObj;
}
function makeStripe(id, color, stripeHeight, scrollTop, onClickStripe) {
// Return an empty div with specified background color and height
var $stripe = $('
');
$stripe.attr('id', 'rainbowStripe' + id);
$stripe.attr('title', 'Click to scroll the tree display');
$stripe.css('background-color', color);
$stripe.height(stripeHeight);
$stripe.click(onClickStripe.bind(null, scrollTop));
return $stripe;
}
function makeRainbowSliderStripes($slider, onClickStripe, svgHeight, stripeColors, stripeTops) {
// Set up the rainbow slider bar for the speciesPicker.
@@ -1083,37 +1090,35 @@
}
} 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 (dbDbTree) {
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);
} else {
$('#speciesTreeContainer').html(getBetterBrowserMessage);
@@ -1536,56 +1541,64 @@
$form.submit();
}
function replaceHgsidInLinks() {
// Substitute '$hgsid' with real hgsid in
href's.
$('a').each(function(ix, aEl) {
var href = aEl.getAttribute('href');
if (href && href.indexOf('$hgsid') >= 0) {
aEl.setAttribute('href', href.replace('$hgsid', window.hgsid));
}
});
}
function init() {
// Boot up the page; initialize elements and install event handlers.
+ var searchObj = {};
+ // We need a bound function to pass into autocompleteCat.init below;
+ // however, autocompleteFromTree is even slower than drawing the tree because of
+ // all the copying. So bind now, fill in searchObj later.
+ var processSpeciesResults = processSpeciesAutocompleteItems.bind(null, searchObj);
cart.setCgi('hgGateway');
cart.debug(debugCartJson);
// Get state from cart
cart.send({ getUiState: {} }, handleRefreshState);
cart.flush();
+ // Prune inactive genomes from dbDbTree.
+ var activeTaxIds = _.invert(activeGenomes);
+ if (dbDbTree && ! pruneInactive(dbDbTree, activeGenomes, activeTaxIds)) {
+ // no more dbDbTree descendants left after pruning
+ dbDbTree = null;
+ }
- // When page has loaded, draw the species tree, do layout adjustments and
- // initialize event handlers.
+ // When page has loaded, do layout adjustments and initialize event handlers.
$(function() {
- var searchObj = autocompleteFromTree(dbDbTree);
- var processSpeciesResults = processSpeciesAutocompleteItems.bind(null, searchObj);
scrollbarWidth = findScrollbarWidth();
- drawSpeciesPicker();
setRightColumnWidth();
setupFavIcons();
autocompleteCat.init($('#speciesSearch'),
{ baseUrl: 'hgGateway?hggw_term=',
watermark: speciesWatermark,
onSelect: setDbFromAutocomplete,
onServerReply: processSpeciesResults,
enterSelectsIdentical: true });
- updateFindPositionSection(uiState);
$('#selectAssembly').change(onChangeDbMenu);
$('#positionDisplay').click(onClickCopyPosition);
$('#copyPosition').click(onClickCopyPosition);
$('.jwGoButtonContainer').click(goToHgTracks);
$(window).resize(setRightColumnWidth.bind(null, scrollbarWidth));
$(window).resize(updateGoButtonPosition);
replaceHgsidInLinks();
+ // Fill in searchObj here once everything is displayed.
+ autocompleteFromTree(dbDbTree, searchObj);
});
}
return { init: init,
// For use by speciesTree.draw SVG (text-only onclick):
onClickSpeciesLabel: onClickSpeciesLabel,
onClickHubName: onClickHubName
};
}()); // hgGateway
hgGateway.init();