@gmod/jbrowse
Version:
JBrowse - client-side genome browser
184 lines (166 loc) • 7.26 kB
JavaScript
define( ['dojo/_base/declare',
'dojo/_base/array',
'dojo/promise/all',
'JBrowse/Util',
'JBrowse/View/Track/HTMLFeatures',
'JBrowse/View/Track/_AlignmentsMixin'
],
function(
declare,
array,
all,
Util,
HTMLFeatures,
AlignmentsMixin
) {
// return declare( HTMLFeatures,
return declare( [ HTMLFeatures, AlignmentsMixin],
/**
* @lends JBrowse.View.Track.Alignments
*/
{
_defaultConfig: function() {
return Util.deepUpdate(
dojo.clone( this.inherited(arguments) ),
{
maxFeatureScreenDensity: 1.5,
layoutPitchY: 4,
hideDuplicateReads: true,
hideQCFailingReads: true,
hideSecondary: true,
hideSupplementary: true,
hideMissingMatepairs: false,
hideImproperPairs: false,
hideUnmapped: true,
hideUnsplicedReads: false,
hideForwardStrand: false,
hideReverseStrand: false,
style: {
_defaultLabelScale: 50,
className: 'alignment',
arrowheadClass: 'arrowhead',
centerChildrenVertically: true,
showMismatches: true,
showSubfeatures: false,
showLabels: false
}
}
);
},
renderFeature: function( feature, uniqueId, block, scale, labelScale, descriptionScale,
containerStart, containerEnd ) {
var featDiv = this.inherited( arguments );
if( ! featDiv )
return null;
var displayStart = Math.max( feature.get('start'), containerStart );
var displayEnd = Math.min( feature.get('end'), containerEnd );
if( this.config.style.showMismatches ) {
this._drawMismatches( feature, featDiv, scale, displayStart, displayEnd );
}
// if this feature is part of a multi-segment read, and not
// all of its segments are aligned, add missing_mate to its
// class
if( feature.get('multi_segment_template') && !feature.get('multi_segment_all_aligned') )
featDiv.className += ' missing_mate';
return featDiv;
},
handleSubFeatures: function( feature, featDiv,
displayStart, displayEnd, block ) {
if( this.config.style.showSubfeatures ) {
this.inherited(arguments);
}
},
/**
* draw base-mismatches on the feature
*/
_drawMismatches: function( feature, featDiv, scale, displayStart, displayEnd ) {
var featLength = displayEnd - displayStart;
// recall: scale is pixels/basepair
if ( featLength*scale > 1 ) {
var mismatches = this._getMismatches( feature );
var charSize = this.getCharacterMeasurements();
var drawChars = scale >= charSize.w;
array.forEach( mismatches, function( mismatch ) {
var start = feature.get('start') + mismatch.start;
var end = start + mismatch.length;
// if the feature has been truncated to where it doesn't cover
// this mismatch anymore, just skip this mismatch
if ( end <= displayStart || start >= displayEnd )
return;
var base = mismatch.base;
var mDisplayStart = Math.max( start, displayStart );
var mDisplayEnd = Math.min( end, displayEnd );
var mDisplayWidth = mDisplayEnd - mDisplayStart;
var overall = dojo.create('span', {
className: mismatch.type + ' base_'+base.toLowerCase(),
style: {
position: 'absolute',
left: 100 * ( mDisplayStart - displayStart)/featLength + '%',
width: scale*mDisplayWidth>1 ? 100 * mDisplayWidth/featLength + '%' : '1px'
}
}, featDiv );
// give the mismatch a mouseover if not drawing a character with the mismatch base
if( ! drawChars )
overall.title = base;
if( drawChars && mismatch.length <= 20 ) {
for( var i = 0; i<mismatch.length; i++ ) {
var basePosition = start + i;
if( basePosition >= mDisplayStart && basePosition <= mDisplayEnd ) {
dojo.create('span',{
className: 'base base_'+base.toLowerCase(),
style: {
position: 'absolute',
width: scale+'px',
left: (basePosition-mDisplayStart)/mDisplayWidth*100 + '%'
},
innerHTML: base
}, overall );
}
}
}
}, this );
}
},
/**
* @returns {Object} containing <code>h</code> and <code>w</code>,
* in pixels, of the characters being used for sequences
*/
getCharacterMeasurements: function() {
if( !this._measurements )
this._measurements = this._measureSequenceCharacterSize( this.div );
return this._measurements;
},
/**
* Conducts a test with DOM elements to measure sequence text width
* and height.
*/
_measureSequenceCharacterSize: function( containerElement ) {
var widthTest = dojo.create('div', {
innerHTML: '<span class="base mismatch">A</span>'
+'<span class="base mismatch">C</span>'
+'<span class="base mismatch">T</span>'
+'<span class="base mismatch">G</span>'
+'<span class="base mismatch">N</span>',
style: {
visibility: 'hidden',
position: 'absolute',
left: '0px'
}
}, containerElement );
var result = {
w: widthTest.clientWidth / 5,
h: widthTest.clientHeight
};
containerElement.removeChild(widthTest);
return result;
},
_trackMenuOptions: function() {
return all([ this.inherited(arguments), this._alignmentsFilterTrackMenuOptions() ])
.then( function( options ) {
var o = options.shift();
options.unshift({ type: 'dijit/MenuSeparator' } );
return o.concat.apply( o, options );
});
}
});
});