From 44b77d6f4cdf6754b9cf33f231b441e2d72d67aa Mon Sep 17 00:00:00 2001 From: gregg Date: Thu, 13 Dec 2012 07:09:21 -0800 Subject: [PATCH] Added dynamic handling of CDS/UTR/exon subfeatures (to support exon-based selection) in DraggableHTMLFeatures. Handles case with no CDS but 'wholeCDS' subfeature. Handles case with CDS and UTR and exons. Handles case with CDS and UTR but no exons. Handles sequence ontology types that are descendants of CDS, UTR, exon as well. --- .../js/View/Track/DraggableHTMLFeatures.js | 190 ++++++++++++++---- 1 file changed, 151 insertions(+), 39 deletions(-) diff --git a/plugins/WebApollo/js/View/Track/DraggableHTMLFeatures.js b/plugins/WebApollo/js/View/Track/DraggableHTMLFeatures.js index 330c98c1fb..bfd457267b 100644 --- a/plugins/WebApollo/js/View/Track/DraggableHTMLFeatures.js +++ b/plugins/WebApollo/js/View/Track/DraggableHTMLFeatures.js @@ -9,9 +9,10 @@ define( [ 'dijit/Dialog', 'jquery', 'jqueryui/draggable', - 'JBrowse/Util' + 'JBrowse/Util', + 'JBrowse/Model/SimpleFeature' ], - function( declare, array, HTMLFeatureTrack, FeatureSelectionManager, dijitMenu, dijitMenuItem, dijitCheckedMenuItem, dijitDialog, $, draggable, Util ) { + function( declare, array, HTMLFeatureTrack, FeatureSelectionManager, dijitMenu, dijitMenuItem, dijitCheckedMenuItem, dijitDialog, $, draggable, Util, SimpleFeature ) { /* Subclass of FeatureTrack that allows features to be selected, and dragged and dropped into the annotation track to create annotations. @@ -340,6 +341,148 @@ var draggableTrack = declare( HTMLFeatureTrack, return subfeatdiv; }, + _subfeatSorter: function( a, b ) { + var as = a.get('start'); + var bs = b.get('start'); + if ( as == bs ) { return 0; } + else if ( as > bs ) { return 1; } + else if ( as < bs ) { return -1; } + else { return 0; /* shouldn't fall through to here */ } + }, + + + /** + * if feature has translated region (CDS, wholeCDS, start_codon, ???), + * reworks feature's subfeatures for more annotation-editing-friendly selection + * + * Assumes: + * if translated, will either have + * CDS-ish term for each coding segment + * wholeCDS from start of translation to end of translation (so already pre-processed) + * mutually exclusive (either have CDS, or wholeCDS, but not both) + * if wholeCDS present, then pre-processed (no UTRs) + * if any exon-ish types present, then _all_ exons are present with exon-ish types + */ + _processTranslation: function( feature ) { + var track = this; + + var feat_type = feature.get('type'); + + // most very dense genomic feature tracks do not have CDS. Trying to minimize overhead for that case -- + // keep list of types that NEVER have CDS children (match, alignment, repeat, etc.) + // (WARNING in this case not sorting, but sorting (currently) only needed for features with CDS (for reading frame calcs)) + if (this.webapollo.neverHasCDS[feat_type]) { + feature.normalized = true; + return; + } + var subfeats = feature.get('subfeatures'); + + // var cds = subfeats.filter( function(feat) { return feat.get('type') === 'CDS'; } ); + var cds = subfeats.filter( function(feat) { + return track.webapollo.cdsTerms[feat.get('type')]; + } ); + var wholeCDS = subfeats.filter( function(feat) { return feat.get('type') === 'wholeCDS'; } ); + + // most very dense genomic feature tracks do not have CDS. Trying to minimize overhead for that case -- + // if no CDS, no wholeCDS, consider normalized + // (WARNING in this case not sorting, but sorting (currently) only needed for features with CDS (for reading frame calcs)) + // + if (cds.length === 0 && wholeCDS.length === 0) { + feature.normalized = true; + return; + } + + var newsubs; + // wholeCDS is specific to WebApollo, if seen can assume no CDS, and UTR/exon already normalized + if (wholeCDS.length > 0) { + // extract wholecds from subfeats, then sort subfeats + feature.wholeCDS = wholeCDS[0]; + newsubs = subfeats.filter( function(feat) { return feat.get('type') !== 'wholeCDS'; } ); + } + + // if has a CDS, remove CDS from subfeats and sort exons + else if (cds.length > 0) { + cds.sort(this._subfeatSorter); + var cdsmin = cds[0].get('start'); + var cdsmax = cds[cds.length-1].get('end'); + feature.wholeCDS = new SimpleFeature({ parent: feature, + data: { start: cdsmin, end: cdsmax, type: 'wholeCDS', + strand: feature.get('strand') } + } ); + var hasExons = false; + for (var i=0; i 0, guaranteed to have at least one CDS + var exonCount = 0; + var prevStart, prevEnd; + // scan through sorted subfeats, joining abutting UTR/CDS regions + for (var i=0; i bs ? 1 : - as < bs ? -1 : 0; - }); - if( cds.length ) { - return { start: cds[0].get('start'), - end: cds[cds.length-1].get('end'), - get: function(n) { return this[n]; } - }; - } - else { - return null; - } - }).call(this); - } -*/ if (wholeCDS) { var cdsStart = wholeCDS.get('start');