diff --git a/tests/js/EditTrack.spec.js b/tests/js/EditTrack.spec.js index aa144b6f..75030094 100644 --- a/tests/js/EditTrack.spec.js +++ b/tests/js/EditTrack.spec.js @@ -103,7 +103,7 @@ describe( "Edit Track", function() { }); it( 'tests comparison function', function() { - expect(compareFeatures(transcript_data["input"][0], transcript_data["input"][0])).toBe(true); + expect(compareFeatures(transcript_data.input[0], transcript_data.input[0])).toBe(true); }); it('tests getWholeCDSCoordinates', function() { @@ -145,17 +145,20 @@ describe( "Edit Track", function() { }); it( 'tests resizeExon', function() { - exon = editTrack.filterExons(transcript_data["input"][0])[0]; - var right = 17120; - var left = exon.get('start'); - outTranscript = editTrack.resizeExon(refSeq, transcript_data["input"][0], exon, left, right); - expect(compareFeatures(transcript_data["resize"][0], outTranscript)).toBe(true); - - exon = editTrack.filterExons(transcript_data["input"][1])[1]; - var right = exon.get('end') + 3; - var left = exon.get('start'); - outTranscript = editTrack.resizeExon(refSeq, transcript_data["input"][1], exon, left, right); - expect(compareFeatures(transcript_data["resize"][2], outTranscript)).toBe(true); + var right, left; + + exon = editTrack.filterExons(transcript_data.input[0])[0]; + right = 17120; + left = exon.get('start'); + outTranscript = editTrack.resizeExon(refSeq, transcript_data.input[0], exon, left, right); + expect(compareFeatures(transcript_data.resize[0], outTranscript)).toBe(true); + + exon = editTrack.filterExons(transcript_data.input[1])[1]; + right = exon.get('end') + 3; + left = exon.get('start'); + outTranscript = editTrack.resizeExon(refSeq, transcript_data.input[1], exon, left, right); + expect(compareFeatures(transcript_data.resize[2], outTranscript)).toBe(true); + }); it( 'tests areOnSameStrand', function() { diff --git a/www/JBrowse/View/Track/EditTrack.js b/www/JBrowse/View/Track/EditTrack.js index b2582de1..0532bca0 100644 --- a/www/JBrowse/View/Track/EditTrack.js +++ b/www/JBrowse/View/Track/EditTrack.js @@ -613,34 +613,15 @@ var EditTrack = declare(DraggableFeatureTrack, return; } - var _exons, exons = []; + var _exons; _exons = this.filterExons(transcript); _exons = _.reject(_exons, function (exon) { return exon === exonToResize; }); if (left !== right) { _exons.push(this.copyFeature(exonToResize, {start: left, end: right})); } - _exons = this.sortAnnotationsByLocation(_exons); - _.each(_exons, _.bind(function (f) { - var last = exons[exons.length - 1]; - if (last && (f.get('start') - last.get('end') <= 1)) { - last.set('end', Math.max(last.get('end'), f.get('end'))); - } - else { - exons.push(this.copyFeature(f)); - } - }, this)); - var newTranscript = this.createTranscript(exons, transcript.get('name')); var translationStart = this.getTranslationStart(transcript); - if (translationStart) { - if (translationStart < newTranscript.get('start')) { - translationStart = newTranscript.get('start'); - } - if (translationStart > newTranscript.get('end')) { - translationStart = newTranscript.get('end'); - } - newTranscript = this.setORF(refSeq, newTranscript, translationStart); - } + var newTranscript = this.createTranscript(_exons, transcript.get('name'), refSeq, translationStart); return newTranscript; }, @@ -732,17 +713,8 @@ var EditTrack = declare(DraggableFeatureTrack, var exons = _.reject(this.filterExons(transcript), function (exon) { return _.indexOf(exonsToDelete, exon) !== -1; }); - var newTranscript = this.createTranscript(exons, transcript.get('name')); var translationStart = this.getTranslationStart(transcript); - if (translationStart) { - if (translationStart < newTranscript.get('start')) { - translationStart = newTranscript.get('start'); - } - if (translationStart > newTranscript.get('end')) { - translationStart = newTranscript.get('end'); - } - newTranscript = this.setORF(refSeq, newTranscript, translationStart); - } + var newTranscript = this.createTranscript(exons, transcript.get('name'), translationStart); return newTranscript; }, @@ -782,24 +754,10 @@ var EditTrack = declare(DraggableFeatureTrack, exons = exons.concat(this.filterExons(transcript)); }, this)); exons = this.sortAnnotationsByLocation(exons); + var name = 'afra-' + exons[0].get('seq_id') + '-mRNA-' + counter++; - // Combine partially or fully overlapping, and immediately adjacent - // exons into one. - var newexons = []; - _.each(exons, _.bind(function (f) { - var last = newexons[newexons.length - 1]; - if (last && (f.get('start') - last.get('end') <= 1)) { // we are looking for introns - newexons[newexons.length - 1] = this.copyFeature(last, {end: Math.max(last.get('end'), f.get('end'))}); - } - else { - newexons.push(f); - } - }, this)); + var newTranscript = this.createTranscript(exons, name, refSeq, translationStart); - // Create new transcript from the processed exons, and insert CDS. - var newTranscript = this.createTranscript(newexons); - newTranscript = this.setORF(refSeq, newTranscript, translationStart); - newTranscript.set('name', 'afra-' + newTranscript.get('seq_id') + '-mRNA-' + counter++); return newTranscript; }, @@ -1069,17 +1027,48 @@ var EditTrack = declare(DraggableFeatureTrack, return transcript; }, - createTranscript: function (subfeatures, name) { + /** + * Create Transcript from the given subfeatures + * + * createTranscript also combines partially or fully overlapping exons. If + * translation Start is not specified then all the non exonic subfeatures + * remain intact. `setORF` or `setCDS` is called on the created + * simpleFeature depeding on if translationStart and translationStop are + * specified. + * If only translation start is given then setORF is called. And if both + * translationStart and translationStop are given then setCDS is called. + **/ + createTranscript: function (subfeatures, name, refSeq, translationStart, translationStop) { // maintain a count of subfeatures seen, indexed by type var count = {}; + var exons = _.filter(subfeatures, function (f) { return f.get("type") === "exon";}); + exons = this.sortAnnotationsByLocation(exons); + + // Combine partially or fully overlapping, and immediately adjacent + // exons into one. + var newexons = []; + _.each(exons, _.bind(function (f) { + var last = newexons[newexons.length - 1]; + if (last && (f.get('start') - last.get('end') <= 0)) { // we are looking for introns + newexons[newexons.length - 1] = this.copyFeature(last, {end: Math.max(last.get('end'), f.get('end'))}); + } + else { + newexons.push(f); + } + }, this)); + + var nonExons = _.filter(subfeatures, function (f) { return f.get("type") !== "exon";}); + var newSubfeatures = nonExons.concat(newexons); + newSubfeatures = this.sortAnnotationsByLocation(newSubfeatures); + var transcript = new SimpleFeature({ data: { type: 'transcript', name: name, - seq_id: subfeatures[0].get('seq_id'), - strand: subfeatures[0].get('strand'), - subfeatures: _.map(subfeatures, function (f) { + seq_id: newSubfeatures[0].get('seq_id'), + strand: newSubfeatures[0].get('strand'), + subfeatures: _.map(newSubfeatures, function (f) { var type = f.get('type'); count[type] = count[type] || 1; return { @@ -1099,6 +1088,22 @@ var EditTrack = declare(DraggableFeatureTrack, var fmax = _.max(_.map(subfeatures, function (f) { return f.get('end'); })); transcript.set('start', fmin); transcript.set('end', fmax); + + if (translationStart) { + if (translationStart < fmin) { + translationStart = fmin; + } + if (translationStart > fmax) { + translationStart = fmax; + } + } + + if (!_.isUndefined(translationStart) && !_.isUndefined(refSeq)) { + if (!_.isUndefined(translationStop)) { + transcript = this.setCDS(transcript, translationStart, translationStop); + } + transcript = this.setORF(refSeq, transcript, translationStart); + } return transcript; },