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 this.setLoaded(); 44 } 45 46 SequenceTrack.prototype = new Track(""); 47 48 SequenceTrack.prototype.startZoom = function(destScale, destStart, destEnd) { 49 this.hide(); 50 this.heightUpdate(0); 51 }; 52 53 SequenceTrack.prototype.endZoom = function(destScale, destBlockBases) { 54 if (destScale == this.charWidth) this.show(); 55 Track.prototype.clear.apply(this); 56 }; 57 58 SequenceTrack.prototype.setViewInfo = function(genomeView, numBlocks, 59 trackDiv, labelDiv, 60 widthPct, widthPx, scale) { 61 Track.prototype.setViewInfo.apply(this, [genomeView, numBlocks, 62 trackDiv, labelDiv, 63 widthPct, widthPx, scale]); 64 if (scale == this.charWidth) { 65 this.show(); 66 } else { 67 this.hide(); 68 this.heightUpdate(0); 69 } 70 this.setLabel(this.key); 71 }; 72 73 SequenceTrack.nbsp = String.fromCharCode(160); 74 SequenceTrack.prototype.fillBlock = function(blockIndex, block, 75 leftBlock, rightBlock, 76 leftBase, rightBase, 77 scale, stripeWidth, 78 containerStart, containerEnd) { 79 var that = this; 80 if (scale == this.charWidth) { 81 this.show(); 82 } else { 83 this.hide(); 84 this.heightUpdate(0); 85 } 86 87 if (this.shown) { 88 this.sequenceStore.getRange( this.refSeq, leftBase, rightBase, 89 function( start, end, seq ) { 90 91 // fill with leading blanks if the 92 // sequence does not extend all the way 93 // across our range 94 for( ; start < 0; start++ ) { 95 seq = SequenceTrack.nbsp + seq; //nbsp is an " " entity 96 } 97 98 // make a div to contain the sequences 99 var seqNode = document.createElement("div"); 100 seqNode.className = "sequence"; 101 block.appendChild(seqNode); 102 103 // add a div for the forward strand 104 seqNode.appendChild( that.renderSeqDiv( start, end, seq )); 105 106 // and one for the reverse strand 107 var comp = that.renderSeqDiv( start, end, that.complement(seq) ); 108 comp.className = 'revcom'; 109 seqNode.appendChild( comp ); 110 } 111 ); 112 this.heightUpdate(this.seqHeight, blockIndex); 113 } else { 114 this.heightUpdate(0, blockIndex); 115 } 116 }; 117 118 SequenceTrack.prototype.complement = (function() { 119 var compl_rx = /[ACGT]/gi; 120 121 // from bioperl: tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/ 122 // generated with: 123 // perl -MJSON -E '@l = split "","acgtrymkswhbvdnxACGTRYMKSWHBVDNX"; print to_json({ map { my $in = $_; tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/; $in => $_ } @l})' 124 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"}; 125 126 var compl_func = function(m) { return compl_tbl[m] || SequenceTrack.nbsp; }; 127 return function( seq ) { 128 return seq.replace( compl_rx, compl_func ); 129 }; 130 })(); 131 132 //given the start and end coordinates, and the sequence bases, makes a 133 //div containing the sequence 134 SequenceTrack.prototype.renderSeqDiv = function ( start, end, seq ) { 135 var container = document.createElement("div"); 136 container.appendChild( document.createTextNode( seq ) ); 137 return container; 138 }; 139 140