ideogram
Version:
Chromosome visualization for the web
116 lines (88 loc) • 3.44 kB
JavaScript
/**
* @fileoverview Methods to show (or hide) cytogenetic banding data
*/
import {d3} from '../lib';
function hideUnshownBandLabels() {
var ideo = this;
var bandsToShow = ideo.bandsToShow.join(',');
// Handles edge-case when ideogram consists of one chromosome
// that lacks bands in a genome that has bands (e.g. MT in human)
if (ideo.bandsToShow.length === 0) return;
// d3.selectAll resolves to querySelectorAll (QSA).
// QSA takes a surprisingly long time to complete,
// and scales with the number of selectors.
// Most bands are hidden, so we can optimize by
// Hiding all bands, then QSA'ing and displaying the
// relatively few bands that are shown.
d3.selectAll(ideo.selector + ' .bandLabel, .bandLabelStalk')
.style('display', 'none');
d3.selectAll(bandsToShow).style('display', '');
}
function getPrevRight(prevLabelXRight, prevHiddenBoxIndex, i,
textOffsets, chrModel) {
var prevTextBoxLeft, prevTextBoxWidth;
if (prevHiddenBoxIndex !== i) {
// This getBoundingClientRect() forces Chrome's
// 'Recalculate Style' and 'Layout', which takes 30-40 ms on Chrome.
// TODO: This forced synchronous layout would be nice to eliminate.
// prevTextBox = texts[i].getBoundingClientRect();
// prevLabelXRight = prevTextBox.left + prevTextBox.width;
// TODO: Account for number of characters in prevTextBoxWidth,
// maybe also zoom.
prevTextBoxLeft = textOffsets[chrModel.id][i];
prevTextBoxWidth = 36;
prevLabelXRight = prevTextBoxLeft + prevTextBoxWidth;
}
return prevLabelXRight;
}
function updateShown(indexesToShow, overlapRight, left, pad, prevRight, i,
isBefore) {
var hiddenIndex, doSkip,
thisRight = isBefore ? overlapRight : prevRight;
if (left < pad + thisRight) {
overlapRight = prevRight;
hiddenIndex = i;
doSkip = isBefore;
} else {
indexesToShow.push(i);
}
return [indexesToShow, overlapRight, hiddenIndex, doSkip];
}
function getIndexesToShow(offsets, chrModel) {
var i, hiddenIndex, left, prevRight, doSkip,
indexesToShow = [],
textsLength = offsets[chrModel.id].length,
overlapRight = 0, // Right X coordinate of overlapping label
pad = 5; // text padding
for (i = 0; i < textsLength; i++) {
// Ensures band labels don't overlap
left = offsets[chrModel.id][i];
[indexesToShow, overlapRight, hiddenIndex, doSkip] =
updateShown(indexesToShow, overlapRight, left, pad, prevRight, i, true);
if (doSkip) continue;
prevRight = getPrevRight(prevRight, hiddenIndex, i, offsets, chrModel);
[indexesToShow, overlapRight, hiddenIndex, doSkip] =
updateShown(indexesToShow, overlapRight, left, pad, prevRight, i, false);
}
return indexesToShow;
}
/**
* Sets band labels to display on each chromosome, avoiding label overlap
*/
function setBandsToShow(chrs, textOffsets) {
var index, i, j, indexesToShow, chrModel, selectorsToShow, ithLength,
ideo = this;
ideo.bandsToShow = [];
for (i = 0; i < chrs.length; i++) {
chrModel = chrs[i];
indexesToShow = getIndexesToShow(textOffsets, chrModel);
selectorsToShow = [];
ithLength = indexesToShow.length;
for (j = 0; j < ithLength; j++) {
index = indexesToShow[j];
selectorsToShow.push('#' + chrModel.id + ' .bsbsl-' + index);
}
ideo.bandsToShow = ideo.bandsToShow.concat(selectorsToShow);
}
}
export {hideUnshownBandLabels, setBandsToShow};