1 // VIEW 2 3 /** 4 * Track to display the underlying reference sequence, when zoomed in 5 * far enough. 6 * @class 7 * @constructor 8 * @param {Object} config 9 * key: display text track name 10 * label: internal track name (no spaces or odd characters) 11 * urlTemplate: url of directory in which to find the sequence chunks 12 * chunkSize: size of sequence chunks, in characters 13 * @param {Object} refSeq 14 * start: refseq start 15 * end: refseq end 16 * name: refseq name 17 * @param {Object} browserParams 18 * changeCallback: function to call once JSON is loaded 19 * trackPadding: distance in px between tracks 20 * charWidth: width, in pixels, of sequence base characters 21 * seqHeight: height, in pixels, of sequence elements 22 */ 23 function SequenceTrack(config, refSeq, browserParams) { 24 25 Track.call( this, config.label, config.key, 26 false, browserParams.changeCallback ); 27 28 this.config = config; 29 30 this.charWidth = browserParams.charWidth; 31 this.seqHeight = browserParams.seqHeight; 32 33 this.refSeq = refSeq; 34 35 // TODO: this should be passed into the constructor instead of 36 // being instantiated here 37 this.sequenceStore = new SequenceStore.StaticChunked({ 38 baseUrl: config.baseUrl, 39 urlTemplate: config.urlTemplate, 40 compress: config.compress 41 }); 42 } 43 44 SequenceTrack.prototype = new Track(""); 45 SequenceTrack.prototype.load = function() { 46 window.setTimeout( dojo.hitch( this, 'setLoaded' ), 10 ); 47 }; 48 49 SequenceTrack.prototype.startZoom = function(destScale, destStart, destEnd) { 50 this.hide(); 51 this.heightUpdate(0); 52 }; 53 54 SequenceTrack.prototype.endZoom = function(destScale, destBlockBases) { 55 if (destScale == this.charWidth) this.show(); 56 Track.prototype.clear.apply(this); 57 }; 58 59 SequenceTrack.prototype.setViewInfo = function(genomeView, numBlocks, 60 trackDiv, labelDiv, 61 widthPct, widthPx, scale) { 62 Track.prototype.setViewInfo.apply(this, [genomeView, numBlocks, 63 trackDiv, labelDiv, 64 widthPct, widthPx, scale]); 65 if (scale == this.charWidth) { 66 this.show(); 67 } else { 68 this.hide(); 69 this.heightUpdate(0); 70 } 71 this.setLabel(this.key); 72 }; 73 74 SequenceTrack.nbsp = String.fromCharCode(160); 75 SequenceTrack.prototype.fillBlock = function(blockIndex, block, 76 leftBlock, rightBlock, 77 leftBase, rightBase, 78 scale, stripeWidth, 79 containerStart, containerEnd) { 80 var that = this; 81 if (scale == this.charWidth) { 82 this.show(); 83 } else { 84 this.hide(); 85 this.heightUpdate(0); 86 } 87 88 if (this.shown) { 89 this.sequenceStore.getRange( this.refSeq, leftBase, rightBase, 90 function( start, end, seq ) { 91 92 // fill with leading blanks if the 93 // sequence does not extend all the way 94 // across our range 95 for( ; start < 0; start++ ) { 96 seq = SequenceTrack.nbsp + seq; //nbsp is an " " entity 97 } 98 99 // make a div to contain the sequences 100 var seqNode = document.createElement("div"); 101 seqNode.className = "sequence"; 102 block.appendChild(seqNode); 103 104 // add a div for the forward strand 105 seqNode.appendChild( that.renderSeqDiv( start, end, seq )); 106 107 // and one for the reverse strand 108 var comp = that.renderSeqDiv( start, end, that.complement(seq) ); 109 comp.className = 'revcom'; 110 seqNode.appendChild( comp ); 111 } 112 ); 113 this.heightUpdate(this.seqHeight, blockIndex); 114 } else { 115 this.heightUpdate(0, blockIndex); 116 } 117 }; 118 119 SequenceTrack.prototype.complement = (function() { 120 var compl_rx = /[ACGT]/gi; 121 122 // from bioperl: tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/ 123 // generated with: 124 // perl -MJSON -E '@l = split "","acgtrymkswhbvdnxACGTRYMKSWHBVDNX"; print to_json({ map { my $in = $_; tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/; $in => $_ } @l})' 125 var compl_tbl = {"S":"S","w":"w","T":"A","r":"y","a":"t","N":"N","K":"M","x":"x","d":"h","Y":"R","V":"B","y":"r","M":"K","h":"d","k":"m","C":"G","g":"c","t":"a","A":"T","n":"n","W":"W","X":"X","m":"k","v":"b","B":"V","s":"s","H":"D","c":"g","D":"H","b":"v","R":"Y","G":"C"}; 126 127 var compl_func = function(m) { return compl_tbl[m] || SequenceTrack.nbsp; }; 128 return function( seq ) { 129 return seq.replace( compl_rx, compl_func ); 130 }; 131 })(); 132 133 //given the start and end coordinates, and the sequence bases, makes a 134 //div containing the sequence 135 SequenceTrack.prototype.renderSeqDiv = function ( start, end, seq ) { 136 var container = document.createElement("div"); 137 container.appendChild( document.createTextNode( seq ) ); 138 return container; 139 }; 140 141