@gmod/jbrowse
Version:
JBrowse - client-side genome browser
152 lines (136 loc) • 5.12 kB
JavaScript
const { TabixIndexedFile } = cjsRequire('@gmod/tabix')
const VCF = cjsRequire('@gmod/vcf')
define([
'dojo/_base/declare',
'JBrowse/Errors',
'dojo/_base/lang',
'JBrowse/Store/SeqFeature',
'JBrowse/Store/DeferredStatsMixin',
'JBrowse/Store/DeferredFeaturesMixin',
'JBrowse/Store/SeqFeature/IndexedStatsEstimationMixin',
'JBrowse/Model/XHRBlob',
'JBrowse/Model/BlobFilehandleWrapper',
'JBrowse/Model/VCFFeature',
],
function(
declare,
Errors,
lang,
SeqFeatureStore,
DeferredStatsMixin,
DeferredFeaturesMixin,
IndexedStatsEstimationMixin,
XHRBlob,
BlobFilehandleWrapper,
VCFFeature,
) {
return declare( [ SeqFeatureStore, DeferredStatsMixin, DeferredFeaturesMixin, IndexedStatsEstimationMixin],
{
constructor( args ) {
var thisB = this;
var csiBlob, tbiBlob;
if(args.csi || this.config.csiUrlTemplate) {
csiBlob = new BlobFilehandleWrapper(args.csi ||
new XHRBlob(
this.resolveUrl(
this.getConf('csiUrlTemplate',[])
)
)
);
} else {
tbiBlob = new BlobFilehandleWrapper(args.tbi ||
new XHRBlob(
this.resolveUrl(
this.getConf('tbiUrlTemplate',[]) || this.getConf('urlTemplate',[])+'.tbi'
)
)
);
}
var fileBlob = new BlobFilehandleWrapper(args.file ||
new XHRBlob(
this.resolveUrl( this.getConf('urlTemplate',[]) ),
{ expectRanges: true }
)
);
this.fileBlob = fileBlob
this.indexedData = new TabixIndexedFile({
tbiFilehandle: tbiBlob,
csiFilehandle: csiBlob,
filehandle: fileBlob,
chunkSizeLimit: args.chunkSizeLimit || 1000000,
renameRefSeqs: n => this.browser.regularizeReferenceName(n)
});
this.getParser()
.then( function( parser ) {
thisB._deferred.features.resolve({success:true});
thisB._estimateGlobalStats()
.then(
function( stats ) {
thisB.globalStats = stats;
thisB._deferred.stats.resolve( stats );
},
lang.hitch( thisB, '_failAllDeferred' )
);
},
lang.hitch( thisB, '_failAllDeferred' )
);
},
getParser() {
if (!this._parser) {
this._parser = this.indexedData.getHeader()
.then(header => new VCF({header: header}))
}
return this._parser
},
_getFeatures( query, featureCallback, finishedCallback, errorCallback ) {
var thisB = this;
thisB.getParser().then(parser => {
const regularizedReferenceName = this.browser.regularizeReferenceName(query.ref)
thisB.indexedData.getLines(
regularizedReferenceName,
query.start,
query.end,
line => {
const variant = parser.parseLine(line)
const feature = new VCFFeature({
variant: variant,
parser: parser,
id: variant.ID ?
variant.ID[0] :
`chr${variant.CHROM}_pos${variant.POS}_ref${variant.REF}_alt${variant.ALT}`
})
featureCallback(feature)
}
)
.then(finishedCallback, error => {
if (errorCallback) {
if (error.message && error.message.indexOf('Too much data') >= 0) {
error = new Errors.DataOverflow(error.message)
}
errorCallback(error)
} else
console.error(error)
})
})
.catch(errorCallback)
},
/**
* Interrogate whether a store has data for a given reference
* sequence. Calls the given callback with either true or false.
*
* Implemented as a binary interrogation because some stores are
* smart enough to regularize reference sequence names, while
* others are not.
*/
hasRefSeq( seqName, callback, errorCallback ) {
return this.indexedData.index.hasRefSeq( seqName, callback, errorCallback );
},
saveStore() {
return {
urlTemplate: this.config.file.url,
tbiUrlTemplate: ((this.config.tbi)||{}).url,
csiUrlTemplate: ((this.config.csi)||{}).url
};
}
});
});