]> www.average.org Git - mkgallery.git/blob - include/show.js
fix image centering issue
[mkgallery.git] / include / show.js
1 /*
2         $Id$
3
4         This is a part of mkgallery.pl suite
5         http://www.average.org/mkgallery/
6
7         Uses mootools (1.2) http://www.mootools.net/
8         Inspired by slideshow http://www.phatfusion.net/slideshow/
9 */
10
11 /*
12         Slideshow
13
14   - On show image: find this and next urls; put in place
15     those that are already here; free unneeded; initiate download of
16     the rest; if needed image is ready then initiate "transitioning", else
17     initiate "loading".
18   - On load complete: if this is the target image, initiate "transitioning".
19   - On "loading": show "loading" image
20   - On "transitioning": hide "loading" image; initiate FX animation to the
21     needed image.
22   - On animation complete: blank previous image; if "playing" then schedule
23     autoswitch to next image in the future.
24   - On autoswitch to next image: if "playing" then switch to next image.
25   - On switch to next image: if next exists, show next image, else show
26     "last image" message.
27   - On switch to prev image: if prev exists, show prev image, else show
28     "first image" message.
29   - On "play": make "playing"; switch to next image.
30   - On "stop": if "playing" cancel autoswitch; break "playing".
31   - On "start show": set up things; set "playing" state; show needed image.
32   - On "stop show": cancel any schedules, hide things.
33   - On resize: recalculate existing image size and position; determine
34     what image is needed; if it is not the one on display then request
35     "show image" for the new image.
36 */
37
38 var Show = new Class({
39
40         getOptions: function(){
41                 return {
42                         cbStart: function(){ alert('show start undefined'); },
43                         cbExit: function(){ alert('show exit undefined'); },
44                         percentage: 98,
45                         delay: 5000,
46                         fxduration: 200,
47                 }
48         },
49
50         initialize: function(vimgs, container, controls, options){
51                 this.setOptions(this.getOptions(), options);
52                 this.vimgs = vimgs;
53                 this.container = container;
54                 this.controls = controls;
55                 this.controls.registershow(this);
56                 this.timer = 0;
57                 this.delay = this.options.delay;
58                 this.cache = {
59                         prev: {},
60                         curr: {},
61                         next: {},
62                 };
63                 this.updatecoords();
64                 this.prevdisplay = new Element('img').
65                         setStyle('opacity', 0).
66                         injectInside(this.container.container);
67                 this.ondisplay = new Element('img').
68                         setStyle('opacity', 0).
69                         injectInside(this.container.container);
70                 this.loadingdiv = new Element('div').
71                 addClass('loading').setStyles({
72                         position: 'absolute',
73                         top: 0,
74                         left: 0,
75                         zIndex: 4,
76                         display: 'none',
77                         width: this.coords.width,
78                         height: this.coords.height,
79                 }).injectInside(this.container.container);
80
81                 window.addEvent('resize', this.resizer.bind(this))
82         },
83
84         /* event handler for window resize */
85
86         resizer: function(){
87                 this.updatecoords();
88                 var newstyle = this.calcsize(this.cache.curr);
89                 this.ondisplay.setStyles(newstyle);
90                 /* check if we need reload */
91         },
92
93         /* prev, play, stop, next, exit, comm are methods for button presses */
94
95         prev: function(){
96                 if (this.currentid > 0) {
97                         this.show(this.currentid-1);
98                 } else {
99                         alert('show.prev called beyond first element');
100                 }
101         },
102
103         stop: function(){
104                 if (this.isplaying) { $clear(this.timer); }
105                 this.isplaying = false;
106                 $clear(this.timer);
107                 this.controls.running(0);
108         },
109
110         play: function(){
111                 this.isplaying = true;
112                 this.timer = this.autonext.delay(this.delay,this);
113                 this.controls.running(1);
114         },
115
116         next: function(){
117                 if (this.currentid < this.vimgs.length-1) {
118                         this.show(this.currentid+1);
119                 } else {
120                         alert('show.next called beyond last element');
121                 }
122         },
123
124         exit: function(){
125                 if (this.isplaying) { $clear(this.timer); }
126                 this.prevdisplay.setStyle('display', 'none');
127                 this.ondisplay.setStyle('display', 'none');
128                 this.stopfx();
129                 this.options.cbExit();
130         },
131
132         comm: function(){
133                 /* alert('show.comm called, do nothing'); */
134         },
135
136         /* Entry point: called to start doing things */
137
138         start: function(id, play){
139                 this.options.cbStart();
140                 this.isplaying = play;
141                 this.controls.running(this.isplaying);
142                 this.updatecoords();
143                 this.show(id);
144                 return false; /* to make it usable from href links */
145         },
146
147         /* "Private" methods to do the real job */
148
149         show: function(id){
150                 /* alert('called show.show('+id+')'); */
151                 this.currentid = id;
152                 var newcache = {
153                         prev: (id > 0)?this.prepare(id-1):{},
154                         curr: this.prepare(id),
155                         next: (id < (this.vimgs.length-1))?this.prepare(id+1):{},
156                 };
157                 delete this.cache;
158                 this.cache = newcache;
159                 if (this.cache.curr.ready) {
160                         this.display(this.cache.curr);
161                 } else {
162                         this.pendingload = true;
163                         this.showloading();
164                 }
165                 this.controls.info(id,this.vimgs.length,
166                                 this.vimgs[id][0],
167                                 this.vimgs[id][1]);
168         },
169
170         prepare: function(id){
171                 var vi;
172                 for (vi=0;vi<this.vimgs[id][2].length-1;vi++) {
173                         if ((this.vimgs[id][2][vi][0] >= this.target.width) ||
174                             (this.vimgs[id][2][vi][1] >= this.target.height)) {
175                                 break;
176                         }
177                 }
178                 /* alert('prepare id='+id+', selected '+vi+' at '+
179                         this.vimgs[id][2][vi][0]+'x'+
180                         this.vimgs[id][2][vi][1]); */
181                 var cachel;
182                 ['prev', 'curr', 'next'].each(function(el){
183                         if (this.cache[el] &&
184                             this.cache[el].id == id &&
185                             this.cache[el].vi == vi) {
186                                 cachel = this.cache[el];
187                         }
188                 }.bind(this));
189                 if (! cachel) {
190                         cachel = {
191                                 id: id,
192                                 vi: vi,
193                                 ready: false,
194                                 url: this.vimgs[id][2][vi][2],
195                         };
196                         cachel.img = this.bgload(cachel);
197                 }
198                 return cachel;
199         },
200
201         bgload: function(cachel){
202                 /* alert('bgload: id='+cachel.id+' vi='+cachel.vi+
203                         ' url='+cachel.url); */
204                 return new Asset.image(this.vimgs[cachel.id][2][cachel.vi][2],{
205                         id: this.vimgs[cachel.id][0],
206                         title: this.vimgs[cachel.id][1],
207                         onload: this.loadcomplete.bind(this,[cachel]),
208                 });
209         },
210
211         loadcomplete: function(cachel){
212                 /* alert('loadcomplete '+cachel.url+' id='+cachel.id+
213                         ' vi='+cachel.vi); */
214                 cachel.ready = true;
215                 if (cachel.id == this.currentid &&
216                     this.pendingload) {
217                         this.pendingload = false;
218                         this.hideloading();
219                         this.display(cachel);
220                 }
221         },
222
223         display: function(cachel){
224                 var newstyle = this.calcsize(cachel);
225                 var newimg = cachel.img.clone();
226                 newimg.setStyles(newstyle);
227                 newimg.setStyles({
228                         zIndex: 3,
229                         opacity: 0,
230                 });
231                 this.prevdisplay.dispose();
232                 this.prevdisplay = this.ondisplay.clone().
233                 setStyle('zIndex', 2).injectInside(this.container.container);
234                 newimg.replaces(this.ondisplay);
235                 this.ondisplay = newimg;
236                 this.effect();
237         },
238
239         effect: function(){
240                 this.fx = new Fx.Tween(this.ondisplay, {
241                         duration: this.options.fxduration,
242                 });
243                 this.fx.addEvent('complete',this.displaycomplete.bind(this));
244                 this.fx.start('opacity', 0, 1);
245         },
246
247         displaycomplete: function(){
248                 this.prevdisplay.setStyle('display', 'none');
249                 if (this.isplaying) {
250                         this.timer = this.autonext.delay(this.delay,this);
251                 }
252         },
253
254         autonext: function(){
255                 if (this.isplaying) {
256                         if (this.currentid < this.vimgs.length-1) {
257                                 this.show(this.currentid+1);
258                         } else {
259                                 this.exit();
260                         }
261                 }
262         },
263
264         calcsize: function(cachel){
265                 var factor = 1;
266                 var candidate;
267                 candidate = this.target.width /
268                                 this.vimgs[cachel.id][2][cachel.vi][0];
269                 if (factor > candidate) { factor = candidate; }
270                 candidate = this.target.height /
271                                 this.vimgs[cachel.id][2][cachel.vi][1];
272                 if (factor > candidate) { factor = candidate; }
273                 var w = Math.round(this.vimgs[cachel.id][2][cachel.vi][0] *
274                         factor);
275                 var h = Math.round(this.vimgs[cachel.id][2][cachel.vi][1] *
276                         factor);
277                 var t = Math.round((this.coords.height-h)/2);
278                 var l = Math.round((this.coords.width-w)/2);
279                 /* alert('new size: '+w+'x'+h+'+'+l+'+'+t); */
280                 return {
281                         position: 'absolute',
282                         top: t+'px',
283                         left: l+'px',
284                         width: w,
285                         height: h,
286                 };
287         },
288
289         showloading: function(){
290                 this.loadingdiv.setStyle('display', 'block');
291         },
292
293         hideloading: function(){
294                 this.loadingdiv.setStyle('display', 'none');
295         },
296
297         stopfx: function(){
298                 if (this.fx) this.fx.cancel();
299         },
300
301         updatecoords: function(){
302                 this.coords = this.container.getCoordinates();
303                 this.target = {
304                         width: Math.round(this.coords.width *
305                                                 this.options.percentage / 100),
306                         height: Math.round(this.coords.height *
307                                                 this.options.percentage / 100),
308                 };
309                 /* alert('coords: '+this.coords.width+'x'+this.coords.height+
310                      ', target: '+this.target.width+'x'+this.target.height); */
311         },
312
313 });
314 Show.implement(new Options);
315 Show.implement(new Events);
316