@gmod/jbrowse
Version:
JBrowse - client-side genome browser
122 lines (112 loc) • 4.28 kB
JavaScript
class PairedRead {
id() {
return Math.min(this.read1.id(), this.read2.id())
}
get(field) {
return this._get(field.toLowerCase())
}
_get(field) {
if(field === 'start') {
return Math.min(this.read1._get('start'), this.read2._get('start'))
} else if(field === 'end') {
return Math.max(this.read1._get('end'), this.read2._get('end'))
} else if(field === 'name') {
return this.read1._get('name')
} else if(field === 'pair_orientation') {
return this.read1._get('pair_orientation')
} else if(field === 'template_length') {
return this.read1._get('template_length')
} else if(field === 'is_paired') {
return true // simply comes from paired end reads
} else if(field === 'paired_feature') {
return true // it is a combination of two reads
}
}
pairedFeature() { return true }
children() {}
}
function canBePaired(alignment) {
return alignment._get('multi_segment_template') &&
!alignment._get('multi_segment_next_segment_unmapped') &&
alignment._get('seq_id') === alignment._get('next_seq_id') &&
(alignment._get('multi_segment_first') || alignment._get('multi_segment_last')) &&
!(alignment._get('secondary_alignment') || alignment._get('supplementary_alignment'))
}
define([
'dojo/_base/declare',
'JBrowse/Util',
],
function(
declare,
Util,
) {
return declare(null, {
constructor(args) {
this.featureCache = {}
},
pairFeatures(query, records, featCallback, errorCallback) {
const pairCache = {};
for(let i = 0; i < records.length; i++) {
let feat
if (canBePaired(records[i]) && Math.abs(records[i]._get('template_length')) < query.maxInsertSize) {
let name = records[i]._get('name')
feat = pairCache[name]
if (feat) {
if(records[i]._get('multi_segment_first')) {
feat.read1 = records[i]
} else if(records[i]._get('multi_segment_last')) {
feat.read2 = records[i]
} else {
console.log('unable to pair read',records[i])
}
if(feat.read1 && feat.read2) {
delete pairCache[name]
this.featureCache[name] = feat
}
}
else {
feat = new PairedRead()
if(records[i]._get('multi_segment_first')) {
feat.read1 = records[i]
} else if(records[i]._get('multi_segment_last')) {
feat.read2 = records[i]
} else {
console.log('unable to pair read', records[i])
}
pairCache[name] = feat
}
}
else if(Util.intersect(records[i]._get('start'), records[i]._get('end'), query.start, query.end)) {
let feat = records[i]
featCallback(feat)
}
}
// dump paired features
Object.entries(this.featureCache).forEach(([k, v]) => {
if(Util.intersect(v._get('start'), v._get('end'), query.start, query.end)) {
featCallback(v)
}
})
// dump unpaired features from the paircache
Object.entries(pairCache).forEach(([k, v]) => {
if(v.read1) {
if(Util.intersect(v.read1._get('start'), v.read1._get('end'), query.start, query.end)) {
featCallback(v.read1)
}
}
else if(v.read2) {
if(Util.intersect(v.read2._get('start'), v.read2._get('end'), query.start, query.end)) {
featCallback(v.read2)
}
}
})
},
cleanFeatureCache(query) {
Object.entries(this.featureCache).forEach(([k, v]) => {
if(!Util.intersect(v._get('start'), v._get('end'), query.start, query.end)) {
delete this.featureCache[k]
}
})
}
});
});