UNPKG

@gmod/jbrowse

Version:

JBrowse - client-side genome browser

205 lines (182 loc) 6.5 kB
define([ 'dojo/_base/declare', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/Deferred', 'JBrowse/Store/SeqFeature', 'JBrowse/Store/DeferredStatsMixin', 'JBrowse/Store/DeferredFeaturesMixin', 'JBrowse/Store/TabixIndexedFile', 'JBrowse/Store/SeqFeature/IndexedStatsEstimationMixin', 'JBrowse/Model/XHRBlob', 'JBrowse/Model/SimpleFeature', './BED/Parser' ], function( declare, lang, array, Deferred, SeqFeatureStore, DeferredStatsMixin, DeferredFeaturesMixin, TabixIndexedFile, IndexedStatsEstimationMixin, XHRBlob, SimpleFeature, Parser ) { return declare( [ SeqFeatureStore, DeferredStatsMixin, DeferredFeaturesMixin, IndexedStatsEstimationMixin ], { constructor: function( args ) { var thisB = this; var csiBlob, tbiBlob; if(args.csi || this.config.csiUrlTemplate) { csiBlob = args.csi || new XHRBlob( this.resolveUrl( this.getConf('csiUrlTemplate',[]) ) ); } else { tbiBlob = args.tbi || new XHRBlob( this.resolveUrl( this.getConf('tbiUrlTemplate',[]) || this.getConf('urlTemplate',[])+'.tbi' ) ); } var fileBlob = args.file || new XHRBlob( this.resolveUrl( this.getConf('urlTemplate',[]) ), { expectRanges: true } ); this.indexedData = new TabixIndexedFile( { tbi: tbiBlob, csi: csiBlob, file: fileBlob, browser: this.browser, chunkSizeLimit: args.chunkSizeLimit || 1000000 }); this.parser = new Parser({ commentCallback: (this.config.commentCallback || function(i) { }), store: this }); this.getHeader() .then( function( header ) { 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' ) ); }, /**fetch and parse the Header line */ getHeader: function() { var thisB = this; return this._parsedHeader || ( this._parsedHeader = function() { var d = new Deferred(); var reject = lang.hitch( d, 'reject' ); thisB.indexedData.indexLoaded.then( function() { var maxFetch = thisB.indexedData.index.firstDataLine ? (thisB.indexedData.index.firstDataLine.block + thisB.indexedData.data.blockSize - 1) * 2 : null; thisB.indexedData.data.read( 0, maxFetch, function( bytes ) { thisB.parser.parseHeader( new Uint8Array( bytes ) ); d.resolve( thisB.header ); }, reject ); }, reject ); return d; }.call(this)); }, _getFeatures: function(query, featureCallback, finishCallback, errorCallback){ this.getHeader().then(() => { this.indexedData.getLines( query.ref || this.refSeq.name, query.start, query.end, line => { this.applyFeatureTransforms([this.lineToFeature(line)]) .forEach( f => { if(this.config.featureCallback) f = this.config.featureCallback(f) featureCallback(f) }) }, finishCallback, errorCallback ); }, errorCallback); }, supportsFeatureTransforms: true, _featureData: function( data ) { var f = lang.mixin( {}, data ); for( var a in data.matrix ) { f[ a.toLowerCase() ] = data.attributes[a].join(','); } return f; }, _formatFeature: function( data ) { var f = new SimpleFeature({ data: this._featureData( data ), id: data.seq_id + "_"+ data.start + "_" +data.end+ "_" + data.name }); f._reg_seq_id = this.browser.regularizeReferenceName( data.seq_id ); return f; }, //read the line lineToFeature: function( line ){ var fields = line.fields; for (var i = 0; i < fields.length; i++) { if(fields[i] == '.') { fields[i] = null; } } var featureData = { start: line.start, end: line.end, seq_id: line.ref, name: fields[3], score: fields[4] ? +fields[4] : null, strand: {'+':1,'-':-1}[fields[5]] || 0 }; var f = new SimpleFeature({ id: fields.slice(0,5).join('/'), data: featureData, fields: fields }); return f; }, /** * 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: function( seqName, callback, errorCallback ) { return this.indexedData.index.hasRefSeq( seqName, callback, errorCallback ); }, saveStore: function() { return { urlTemplate: this.config.file.url, tbiUrlTemplate: ((this.config.tbi)||{}).url, csiUrlTemplate: ((this.config.csi)||{}).url }; } }); });