1 // VIEW 2 3 /** 4 * A track that displays tiled images (PNGs, or other images) along 5 * the reference sequence. 6 * @class 7 * @extends Track 8 */ 9 function ImageTrack(config, refSeq, browserParams) { 10 Track.call(this, config.label, config.key, 11 false, browserParams.changeCallback); 12 13 if( !refSeq.end ) 14 return; 15 16 this.refSeq = refSeq; 17 this.trackPadding = browserParams.trackPadding || 0; 18 19 this.config = config; 20 21 // TODO: the imagestore should be passed in as an arg to the 22 // constructor, not instantiated here 23 var storeclass = config.backendVersion == 0 ? TiledImageStore.Fixed_v0 : TiledImageStore.Fixed; 24 this.store = new storeclass({ 25 refSeq: refSeq, 26 urlTemplate: config.urlTemplate, 27 baseUrl: config.baseUrl, 28 track: this 29 }); 30 dojo.connect( this.store, 'loadSuccess', this, 'loadSuccess' ); 31 dojo.connect( this.store, 'loadFail', this, 'loadFail' ); 32 } 33 34 ImageTrack.prototype = new Track(""); 35 36 /** 37 * Request that the track load its data. The track will call its own 38 * loadSuccess() function when it is loaded. 39 */ 40 ImageTrack.prototype.load = function() { 41 this.store.load(); 42 }; 43 44 ImageTrack.prototype.loadSuccess = function(o,url) { 45 this.empty = this.store.empty; 46 this.setLoaded(); 47 }; 48 49 ImageTrack.prototype.setViewInfo = function(heightUpdate, numBlocks, 50 trackDiv, labelDiv, 51 widthPct, widthPx, scale) { 52 Track.prototype.setViewInfo.apply( this, arguments ); 53 this.setLabel( this.key ); 54 }; 55 56 ImageTrack.prototype.handleImageError = function(ev) { 57 var img = ev.currentTarget || ev.srcElement; 58 img.style.display = "none"; 59 dojo.stopEvent(ev); 60 }; 61 62 63 /** 64 * @private 65 */ 66 ImageTrack.prototype.makeImageLoadHandler = function( img, blockIndex, blockWidth, composeCallback ) { 67 var handler = dojo.hitch( this, function() { 68 this.imageHeight = img.height; 69 img.style.height = img.height + "px"; 70 img.style.width = (100 * (img.baseWidth / blockWidth)) + "%"; 71 this.heightUpdate( img.height, blockIndex ); 72 if( composeCallback ) 73 composeCallback(); 74 return true; 75 }); 76 77 if( ! dojo.isIE ) 78 return handler; 79 else 80 // in IE, have to delay calling it for a (arbitrary) 1/4 81 // second because the image's height is not always 82 // available when the onload event fires. >:-{ 83 return function() { 84 window.setTimeout(handler,250); 85 }; 86 87 }; 88 89 ImageTrack.prototype.fillBlock = function(blockIndex, block, 90 leftBlock, rightBlock, 91 leftBase, rightBase, 92 scale, stripeWidth, 93 containerStart, containerEnd) { 94 var blockWidth = rightBase - leftBase; 95 var images = this.store.getImages( scale, leftBase, rightBase ); 96 var im; 97 98 dojo.forEach( images, function(im) { 99 im.className = 'image-track'; 100 if (!(im.parentNode && im.parentNode.parentNode)) { 101 im.style.position = "absolute"; 102 im.style.left = (100 * ((im.startBase - leftBase) / blockWidth)) + "%"; 103 switch (this.config.align) { 104 case "top": 105 im.style.top = "0px"; 106 break; 107 case "bottom": 108 default: 109 im.style.bottom = this.trackPadding + "px"; 110 break; 111 } 112 block.appendChild(im); 113 } 114 115 // make an onload handler for when the image is fetched that 116 // will update the height and width of the track 117 var loadhandler = this.makeImageLoadHandler( im, blockIndex, blockWidth ); 118 if( im.complete ) 119 // just call the handler ourselves if the image is already loaded 120 loadhandler(); 121 else 122 // otherwise schedule it 123 dojo.connect( im, "onload", loadhandler ); 124 125 }, this); 126 }; 127 128 ImageTrack.prototype.startZoom = function(destScale, destStart, destEnd) { 129 if (this.empty) return; 130 this.store.clearCache(); 131 this.store.getImages( destScale, destStart, destEnd ); 132 }; 133 134 ImageTrack.prototype.endZoom = function(destScale, destBlockBases) { 135 Track.prototype.clear.apply(this); 136 }; 137 138 ImageTrack.prototype.clear = function() { 139 Track.prototype.clear.apply(this); 140 this.store.clearCache(); 141 }; 142 143 ImageTrack.prototype.transfer = function(sourceBlock, destBlock, scale, 144 containerStart, containerEnd) { 145 if (!(sourceBlock && destBlock)) return; 146 147 var children = sourceBlock.childNodes; 148 var destLeft = destBlock.startBase; 149 var destRight = destBlock.endBase; 150 var im; 151 for (var i = 0; i < children.length; i++) { 152 im = children[i]; 153 if ("startBase" in im) { 154 //if sourceBlock contains an image that overlaps destBlock, 155 if ((im.startBase < destRight) 156 && ((im.startBase + im.baseWidth) > destLeft)) { 157 //move image from sourceBlock to destBlock 158 im.style.left = (100 * ((im.startBase - destLeft) / (destRight - destLeft))) + "%"; 159 destBlock.appendChild(im); 160 } else { 161 // don't move it, and even uncache it 162 this.store.unCacheImage( im ); 163 } 164 } 165 } 166 }; 167 168