ideogram
Version:
Chromosome visualization for the web
286 lines (231 loc) • 7.67 kB
JavaScript
/**
* @fileoveriew Methods for initialization
*/
import {d3, slug} from '../lib';
import {configure} from './configure';
import {finishInit} from './finish-init';
import {writeContainer} from './write-container';
import {shouldFetchBands, fetchBands} from '../bands/fetch';
import {organismMetadata} from './organism-metadata';
function isHeterogameticChromosome(chrModel, chrIndex, ideo) {
var ploidy = ideo.config.ploidy;
return (
'sex' in ideo.config &&
(
ploidy === 2 && ideo.sexChromosomes.index + 1 === chrIndex ||
ideo.config.sex === 'female' && chrModel.name === 'Y'
)
);
}
function prepareChromosomes(bandsArray, chrs, taxid, ideo) {
var j, bands, chromosome, chrModel, chrIndex;
for (j = 0; j < chrs.length; j++) {
chromosome = chrs[j];
if (typeof bandsArray !== 'undefined') bands = bandsArray[j];
chrIndex = j + ideo.config.taxids.indexOf(taxid);
chrModel = ideo.getChromosomeModel(bands, chromosome, taxid, chrIndex);
if (typeof chromosome !== 'string') {
chromosome = chromosome.name.split(' ').slice(-1)[0].replace('chr', '');
}
ideo.chromosomes[taxid][chromosome] = chrModel;
ideo.chromosomesArray.push(chrModel);
if (isHeterogameticChromosome(chrModel, j, ideo)) continue;
ideo.drawChromosome(chrModel);
}
}
function setCoordinateSystem(chrs, ideo) {
if (
typeof chrBands !== 'undefined' &&
chrs.length >= chrBands.length / 2
) {
ideo.coordinateSystem = 'bp';
}
}
/**
* Configures chromosome data and calls downstream chromosome drawing functions
*/
function initDrawChromosomes() {
var taxid, i, chrs, bandsArray,
ideo = this,
taxids = ideo.config.taxids;
for (i = 0; i < taxids.length; i++) {
taxid = taxids[i];
chrs = ideo.config.chromosomes[taxid];
bandsArray = ideo.bandsArray[taxid];
if (!ideo.config.showNonNuclearChromosomes) {
// Remove MT
// TODO: Handle other non-nuclear chromosomes, e.g. CP, AP
chrs = chrs.filter(chr => chr !== 'MT');
if (typeof bandsArray !== 'undefined') {
bandsArray = bandsArray.filter(bands => {
return bands[0].chr !== 'MT';
});
}
}
setCoordinateSystem(chrs, ideo);
ideo.chromosomes[taxid] = {};
ideo.setSexChromosomes(chrs);
prepareChromosomes(bandsArray, chrs, taxid, ideo);
if (ideo.config.showBandLabels) ideo.drawBandLabels(ideo.chromosomes);
ideo.handleRotateOnClick();
ideo._gotChrModels = true; // Prevent issue with errant rat centromeres
}
}
/**
* Attach any click handlers to rotate and toggle chromosomes
*/
function handleRotateOnClick() {
var ideo = this;
if (!('rotatable' in ideo.config && ideo.config.rotatable === false)) {
d3.selectAll(ideo.selector + ' .chromosome-set').on('click', function() {
// Handles click on chromosome graphic or label.
// Label click needed to toggle e.g. human MT
const element = this.children[1];
ideo.rotateAndToggleDisplay(element);
});
} else {
d3.selectAll(ideo.selector).style('cursor', 'default');
}
}
/**
* Called when Ideogram has finished initializing.
* Accounts for certain ideogram properties not being set until
* asynchronous requests succeed, etc.
*/
function onLoad() {
call(this.onLoadCallback);
}
function getBandFileName(taxid, accession, ideo) {
var organism = ideo.organisms[taxid];
var bandFileName = [slug(organism.scientificName)];
var assemblies = organism.assemblies;
var resolution = ideo.config.resolution;
if (accession !== assemblies.default) {
bandFileName.push(accession);
}
if (
taxid === '9606' &&
(accession in assemblies === 'false' &&
Object.values(assemblies).includes(config.assembly) ||
(resolution !== '' && resolution !== 850))
) {
bandFileName.push(resolution);
}
bandFileName = bandFileName.join('-');
var fullyBandedTaxids = ['9606', '10090', '10116'];
if (fullyBandedTaxids.includes(taxid) && !ideo.config.showFullyBanded) {
bandFileName += '-no-bands';
}
bandFileName += '.json';
return bandFileName;
}
function getBandFileNames(taxid, bandFileNames, ideo) {
var organism, assemblies, accession, bandFileName,
config = ideo.config;
organism = ideo.organisms[taxid];
if (!config.assembly) ideo.config.assembly = 'default';
assemblies = organism.assemblies;
if (ideo.assemblyIsAccession()) {
accession = config.assembly;
} else {
accession = assemblies[config.assembly];
}
bandFileName = getBandFileName(taxid, accession, ideo);
var isCustomOrganism = taxid === '-1';
if (taxid in ideo.organismsWithBands || isCustomOrganism) {
bandFileNames[taxid] = bandFileName;
}
return bandFileNames;
}
function prepareContainer(taxid, bandFileNames, t0, ideo) {
if (shouldFetchBands(bandFileNames, taxid, ideo)) {
return fetchBands(bandFileNames, taxid, t0, ideo).then(function() {
return ideo.processBandData(taxid);
});
} else {
return new Promise(function(resolve) {
ideo.processBandData(taxid);
resolve([taxid, undefined]);
});
}
}
function initializeTaxids(ideo) {
return new Promise(function(resolve) {
var organism = ideo.config.organism;
if (typeof organism === 'number') {
// 'organism' is a taxid, e.g. 9606
ideo.getOrganismFromEutils(organism, function() {
ideo.getTaxids(resolve);
});
} else {
ideo.getTaxids(resolve);
}
});
}
function getBandsAndPrepareContainer(taxids, t0, ideo) {
var bandFileNames, i, taxid,
promises = [];
bandFileNames = {};
for (taxid in organismMetadata) {
bandFileNames[taxid] = '';
}
for (i = 0; i < taxids.length; i++) {
taxid = String(taxids[i]);
bandFileNames = getBandFileNames(taxid, bandFileNames, ideo);
promises.push(prepareContainer(taxid, bandFileNames, t0, ideo));
}
Promise.all(promises).then(function(taxidsAndBandsArrays) {
var taxidAndBandsArray, taxid, bandsArray;
for (i = 0; i < taxidsAndBandsArrays.length; i++) {
taxidAndBandsArray = taxidsAndBandsArrays[i];
taxid = taxidAndBandsArray[0];
bandsArray = taxidAndBandsArray[1];
if ('bandsArray' in ideo === false) {
ideo.bandsArray = {};
}
ideo.bandsArray[taxid] = bandsArray;
}
ideo.writeContainer(t0);
});
}
/**
* Initializes an ideogram.
* Sets some high-level properties based on instance configuration,
* fetches band and annotation data if needed, and
* writes an SVG element to the document to contain the ideogram
*/
// Prevents race condition when init is called multiple times in
// quick succession.
// See https://github.com/eweitz/ideogram/pull/154.
var ideoNext = {};
var ideoQueued = {};
var ideoWait = {};
function init(ideo) {
ideo = ideo || this;
var containerId = ideo.config.container;
if (ideoWait[containerId]) {
ideoQueued[containerId] = true;
ideoNext[containerId] = ideo;
} else {
ideoWait[containerId] = true;
initializeTaxids(ideo)
.then(function(taxids) {
var taxid = taxids[0];
ideo.config.taxid = taxid;
ideo.config.taxids = taxids;
ideo.organismScientificName =
ideo.getScientificName(ideo.config.taxid);
var t0 = new Date().getTime();
getBandsAndPrepareContainer(taxids, t0, ideo);
ideoWait[containerId] = false;
if (ideoQueued[containerId]) {
ideoQueued[containerId] = false;
init(ideoNext[containerId]);
}
});
}
}
export {
configure, initDrawChromosomes, handleRotateOnClick,
onLoad, init, finishInit, writeContainer
};