UNPKG

@gmod/jbrowse

Version:

JBrowse - client-side genome browser

257 lines (207 loc) 7.96 kB
define([ 'dojo/_base/declare', 'dojo/_base/array', 'dojox/color/Palette', 'JBrowse/Model/SimpleFeature', 'JBrowse/View/FeatureGlyph/Segments' ], function( declare, array, Palette, SimpleFeature, SegmentsGlyph ) { return declare( SegmentsGlyph, { _defaultConfig: function() { return this._mergeConfigs( this.inherited(arguments), { style: { utrColor: function( feature, variable, glyph, track ) { return glyph._utrColor( glyph.getStyle( feature.parent(), 'color' ) ).toString(); }, utrHeightPercent: 65 }, subParts: 'CDS, UTR, five_prime_UTR, three_prime_UTR', impliedUTRs: false, inferCdsParts: false, subSubParts: () => true, // render sub-subparts by default }); }, _getSubparts: function( f ) { var c = f.children(); if( ! c ) return []; if( c && this.config.inferCdsParts ) c = this._makeCDSs( f, c ); if( c && this.config.impliedUTRs ) c = this._makeUTRs( f, c ); var filtered = []; for( var i = 0; i<c.length; i++ ) if( this._filterSubpart( c[i] ) ) filtered.push( c[i] ); return filtered; }, _makeCDSs: function( parent, subparts ) { // infer CDS parts from exon coordinates var codeStart = Infinity, codeEnd = -Infinity; var i; // gather exons, find coding start and end var type, codeIndices = [], exons = []; for( i = 0; i < subparts.length; i++ ) { type = subparts[i].get('type'); if( /^cds/i.test( type ) ) { // if any CDSs parts are present already, // bail and return all subparts as-is if( /:CDS:/i.test( subparts[i].get('name') ) ) return subparts; codeIndices.push(i); if( codeStart > subparts[i].get('start') ) codeStart = subparts[i].get('start'); if( codeEnd < subparts[i].get('end') ) codeEnd = subparts[i].get('end'); } else { if( /exon/i.test( type ) ) { exons.push( subparts[i] ); } } } // splice out unspliced cds parts codeIndices.sort( function(a,b) { return b - a; } ); for ( i = codeIndices.length - 1; i >= 0; i-- ) subparts.splice(codeIndices[i], 1); // bail if we don't have exons and cds if( !( exons.length && codeStart < Infinity && codeEnd > -Infinity ) ) return subparts; // make sure the exons are sorted by coord exons.sort( function(a,b) { return a.get('start') - b.get('start'); } ); // iterate thru exons again, and calculate cds parts var strand = parent.get('strand'); var codePartStart = Infinity, codePartEnd = -Infinity; for ( i = 0; i < exons.length; i++ ) { var start = exons[i].get('start'); var end = exons[i].get('end'); // CDS containing exon if( codeStart >= start && codeEnd <= end ) { codePartStart = codeStart; codePartEnd = codeEnd; } // 5' terminal CDS part else if( codeStart >= start && codeStart < end ) { codePartStart = codeStart; codePartEnd = end; } // 3' terminal CDS part else if( codeEnd > start && codeEnd <= end ) { codePartStart = start; codePartEnd = codeEnd; } // internal CDS part else if( start < codeEnd && end > codeStart ) { codePartStart = start; codePartEnd = end; } // "splice in" the calculated cds part into subparts // at beginning of _makeCDSs() method, bail if cds subparts are encountered subparts.splice(i, 0, ( new SimpleFeature( { parent: parent, data: { start: codePartStart, end: codePartEnd, strand: strand, type: 'CDS', name: parent.get('uniqueID') + ":CDS:" + i }}))); } // make sure the subparts are sorted by coord subparts.sort( function(a,b) { return a.get('start') - b.get('start'); } ); return subparts; }, _makeUTRs: function( parent, subparts ) { // based on Lincoln's UTR-making code in Bio::Graphics::Glyph::processed_transcript var codeStart = Infinity, codeEnd = -Infinity; var i; var haveLeftUTR, haveRightUTR; // gather exons, find coding start and end, and look for UTRs var type, exons = []; for( i = 0; i<subparts.length; i++ ) { type = subparts[i].get('type'); if( /^cds/i.test( type ) ) { if( codeStart > subparts[i].get('start') ) codeStart = subparts[i].get('start'); if( codeEnd < subparts[i].get('end') ) codeEnd = subparts[i].get('end'); } else if( /exon/i.test( type ) ) { exons.push( subparts[i] ); } else if( this._isUTR( subparts[i] ) ) { haveLeftUTR = subparts[i].get('start') == parent.get('start'); haveRightUTR = subparts[i].get('end') == parent.get('end'); } } // bail if we don't have exons and CDS if( !( exons.length && codeStart < Infinity && codeEnd > -Infinity ) ) return subparts; // make sure the exons are sorted by coord exons.sort( function(a,b) { return a.get('start') - b.get('start'); } ); var strand = parent.get('strand'); // make the left-hand UTRs var start, end; if( ! haveLeftUTR ) for (i=0; i<exons.length; i++) { start = exons[i].get('start'); if ( start >= codeStart ) break; end = codeStart > exons[i].get('end') ? exons[i].get('end') : codeStart; subparts.unshift( new SimpleFeature( { parent: parent, data: { start: start, end: end, strand: strand, type: strand >= 0 ? 'five_prime_UTR' : 'three_prime_UTR' }})); } // make the right-hand UTRs if( ! haveRightUTR ) for (i=exons.length-1; i>=0; i--) { end = exons[i].get('end'); if( end <= codeEnd ) break; start = codeEnd < exons[i].get('start') ? exons[i].get('start') : codeEnd; subparts.push( new SimpleFeature( { parent: parent, data: { start: start, end: end, strand: strand, type: strand >= 0 ? 'three_prime_UTR' : 'five_prime_UTR' }})); } return subparts; }, _utrColor: function( baseColor ) { return (this._palette || (this._palette = Palette.generate( baseColor, "splitComplementary"))).colors[1]; }, _isUTR: function( feature ) { return /(\bUTR|_UTR|untranslated[_\s]region)\b/.test( feature.get('type') || '' ); }, getStyle: function( feature, name ) { if( name == 'color' ) { if( this._isUTR( feature ) ) { return this.getStyle( feature, 'utrColor' ); } } return this.inherited(arguments); }, _getFeatureHeight: function( viewInfo, feature ) { var height = this.inherited( arguments ); if( this._isUTR( feature ) ) return height*this.getStyle(feature,'utrHeightPercent')/100; return height; } }); });