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