@gmod/jbrowse
Version:
JBrowse - client-side genome browser
82 lines (72 loc) • 3.23 kB
JavaScript
/**
* Store class that encapsulates another store, and synthesizes
* quantitative features that give the depth of coverage for the
* features in it.
*/
define([
'dojo/_base/declare',
'JBrowse/Store/SeqFeature',
'JBrowse/Util',
'JBrowse/Model/CoverageFeature'
],
function( declare, SeqFeatureStore, Util, CoverageFeature ) {
return declare( SeqFeatureStore, {
constructor: function( args ) {
this.store = args.store;
},
getGlobalStats: function( callback, errorCallback ) {
callback( {} );
},
getFeatures: function( query, featureCallback, finishCallback, errorCallback ) {
var leftBase = query.start;
var rightBase = query.end;
var scale = query.scale || ( ('basesPerSpan' in query) ? 1/query.basesPerSpan : 10 ); // px/bp
var widthBp = rightBase-leftBase;
var widthPx = widthBp * scale;
var binWidth = Math.ceil( 1/scale ); // in bp
var coverageBins = new Array( Math.ceil( widthBp/binWidth ) );
var binOverlap = function( bp, isRightEnd ) {
var binCoord = (bp-leftBase-1) / binWidth;
var binNumber = Math.floor( binCoord );
var overlap = isRightEnd ? 1-(binCoord-binNumber) : binCoord - binNumber;
return {
bin: binNumber,
overlap: overlap // between 0 and 1: proportion of this bin that the feature overlaps
};
};
this.store.getFeatures(
query,
function( feature ) {
var startBO = binOverlap( feature.get('start'), false );
var endBO = binOverlap( feature.get('end'), true );
// increment start and end partial-overlap bins by proportion of overlap
if( startBO.bin == endBO.bin ) {
coverageBins[startBO.bin] = (coverageBins[startBO.bin] || 0) + endBO.overlap + startBO.overlap - 1;
}
else {
coverageBins[startBO.bin] = (coverageBins[startBO.bin] || 0) + startBO.overlap;
coverageBins[endBO.bin] = (coverageBins[endBO.bin] || 0) + endBO.overlap;
}
// increment completely overlapped interior bins by 1
for( var i = startBO.bin+1; i <= endBO.bin-1; i++ ) {
coverageBins[i] = (coverageBins[i] || 0) + 1;
}
},
function () {
// make fake features from the coverage
for( var i = 0; i < coverageBins.length; i++ ) {
var score = (coverageBins[i] || 0);
var bpOffset = leftBase+binWidth*i;
featureCallback( new CoverageFeature({
start: bpOffset,
end: bpOffset+binWidth,
score: score
}));
}
finishCallback();
},
errorCallback
);
}
});
});