/[drupal]/contributions/modules/slideshowcs/jquery.cross-slide.js
ViewVC logotype

Contents of /contributions/modules/slideshowcs/jquery.cross-slide.js

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Wed Sep 3 13:21:24 2008 UTC (14 months, 3 weeks ago) by davebv
Branch: MAIN
CVS Tags: DRUPAL-6--1-0, DRUPAL-6--1-1, HEAD
Branch point for: DRUPAL-6--1
File MIME type: text/javascript
Initial commit of SlideShowCS module. A fancy slideshow with jquery plugins
1 /*
2 * Copyright 2007 by Tobia Conforto <tobia.conforto@linux.it>
3 *
4 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General
5 * Public License as published by the Free Software Foundation; either version 2 of the License, or (at your
6 * option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
9 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10 * for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with this program; if not, write to
13 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14 *
15 * Versions: 0.1 2007-08-19 Initial release
16 * 2008-08-21 Re-released under GPL v2
17 */
18
19 jQuery.fn.crossSlide = function(opts, plan) {
20 var self = this,
21 self_width = this.width(),
22 self_height = this.height();
23
24 // generic utilities
25 function format(str) {
26 for (var i = 1; i < arguments.length; i++)
27 str = str.replace(new RegExp('\\{' + (i-1) + '}', 'g'), arguments[i]);
28 return str;
29 }
30
31 function dump_obj(o) {
32 var s = '{ ';
33 for (var n in o)
34 s += n + ': ' + o[n] + ', ';
35 return (s == '{ ' ? '{}' : s.slice(0, -2) + ' }');
36 }
37
38 // first preload all the images, while getting their actual width and height
39 (function(proceed) {
40
41 var n_loaded = 0;
42 function loop(i, img) {
43 // for (i = 0; i < plan.length; i++) but with independent var i, img (for the closures)
44 img.onload = function(e) {
45 n_loaded++;
46 plan[i].width = img.width;
47 plan[i].height = img.height;
48 if (n_loaded == plan.length)
49 proceed();
50 }
51 img.src = plan[i].src;
52 if (i + 1 < plan.length)
53 loop(i + 1, new Image());
54 }
55 loop(0, new Image());
56
57 })(function() { // then proceed
58
59 // utility to parse "from" and "to" parameters
60 function parse_position_param(param) {
61 var zoom = 1;
62 var tokens = param.replace(/^\s*|\s*$/g, '').split(/\s+/);
63 if (tokens.length > 3) throw new Error();
64 if (tokens[0] == 'center')
65 if (tokens.length == 1)
66 tokens = ['center', 'center'];
67 else if (tokens.length == 2 && tokens[1].match(/^[\d.]+x$/i))
68 tokens = ['center', 'center', tokens[1]];
69 if (tokens.length == 3)
70 zoom = parseFloat(tokens[2].match(/^([\d.]+)x$/i)[1]);
71 var pos = tokens[0] + ' ' + tokens[1];
72 if (pos == 'left top' || pos == 'top left') return { xrel: 0, yrel: 0, zoom: zoom };
73 if (pos == 'left center' || pos == 'center left') return { xrel: 0, yrel: .5, zoom: zoom };
74 if (pos == 'left bottom' || pos == 'bottom left') return { xrel: 0, yrel: 1, zoom: zoom };
75 if (pos == 'center top' || pos == 'top center') return { xrel: .5, yrel: 0, zoom: zoom };
76 if (pos == 'center center') return { xrel: .5, yrel: .5, zoom: zoom };
77 if (pos == 'center bottom' || pos == 'bottom center') return { xrel: .5, yrel: 1, zoom: zoom };
78 if (pos == 'right top' || pos == 'top right') return { xrel: 1, yrel: 0, zoom: zoom };
79 if (pos == 'right center' || pos == 'center right') return { xrel: 1, yrel: .5, zoom: zoom };
80 if (pos == 'right bottom' || pos == 'bottom right') return { xrel: 1, yrel: 1, zoom: zoom };
81 return {
82 xrel: parseInt(tokens[0].match(/^(\d+)%$/)[1]) / 100,
83 yrel: parseInt(tokens[1].match(/^(\d+)%$/)[1]) / 100,
84 zoom: zoom
85 };
86 }
87
88 // utility to compute the css for a given phase between p.from and p.to
89 // phase = 1: begin fade-in, 2: end fade-in, 3: begin fade-out, 4: end fade-out
90 function position_to_css(p, phase) {
91 switch (phase) {
92 case 1:
93 var pos = 0;
94 break;
95 case 2:
96 var pos = fade_ms / (p.time_ms + 2 * fade_ms);
97 break;
98 case 3:
99 var pos = 1 - fade_ms / (p.time_ms + 2 * fade_ms);
100 break;
101 case 4:
102 var pos = 1;
103 break;
104 }
105 return {
106 left: Math.round(p.from.left + pos * (p.to.left - p.from.left )),
107 top: Math.round(p.from.top + pos * (p.to.top - p.from.top )),
108 width: Math.round(p.from.width + pos * (p.to.width - p.from.width )),
109 height: Math.round(p.from.height + pos * (p.to.height - p.from.height))
110 };
111 }
112
113 // check global params
114 if (! opts.fade)
115 throw 'Missing fade parameter.';
116 if (opts.speed && opts.sleep)
117 throw 'You cannot set both speed and sleep at the same time.';
118 // conversion from sec to ms; from px/sec to px/ms
119 var fade_ms = Math.round(opts.fade * 1000);
120 if (opts.sleep)
121 var sleep = Math.round(opts.sleep * 1000);
122 if (opts.speed)
123 var speed = opts.speed / 1000,
124 fade_px = Math.round(fade_ms * speed);
125
126 // a debug: true option may be added to get a dump of the generated JavaScript code
127 if (opts.debug)
128 var debug = jQuery('<pre><hr/></pre>');
129
130 // set container css
131 self.empty().css({
132 overflow: 'hidden',
133 padding: 0
134 });
135 if (! self.css('position').match(/absolute|relative|fixed/))
136 self.css({ position: 'relative' })
137
138 // prepare each image
139 for (var i in plan) {
140
141 var p = plan[i];
142 if (! p.src)
143 throw format('Missing src parameter in picture {0}.', i + 1);
144
145 if (speed) { // speed/dir mode
146
147 // check parameters and translate speed/dir mode into full mode (from/to/time)
148 switch (p.dir) {
149 case 'up':
150 p.from = { xrel: .5, yrel: 0, zoom: 1 };
151 p.to = { xrel: .5, yrel: 1, zoom: 1 };
152 var slide_px = p.height - self_height - 2 * fade_px;
153 break;
154 case 'down':
155 p.from = { xrel: .5, yrel: 1, zoom: 1 };
156 p.to = { xrel: .5, yrel: 0, zoom: 1 };
157 var slide_px = p.height - self_height - 2 * fade_px;
158 break;
159 case 'left':
160 p.from = { xrel: 0, yrel: .5, zoom: 1 };
161 p.to = { xrel: 1, yrel: .5, zoom: 1 };
162 var slide_px = p.width - self_width - 2 * fade_px;
163 break;
164 case 'right':
165 p.from = { xrel: 1, yrel: .5, zoom: 1 };
166 p.to = { xrel: 0, yrel: .5, zoom: 1 };
167 var slide_px = p.width - self_width - 2 * fade_px;
168 break;
169 default:
170 throw format('Missing or malformed "dir" parameter in picture {0}.', i + 1);
171 }
172 if (slide_px <= 0)
173 throw format('Picture number {0} is too short for the desired fade duration.', i + 1);
174 p.time_ms = Math.round(slide_px / speed);
175
176 } else if (! sleep) { // full mode
177
178 // check and parse parameters
179 if (! p.from || ! p.to || ! p.time)
180 throw format('Missing either speed/sleep option, or from/to/time params in picture {0}.', i + 1);
181 try {
182 p.from = parse_position_param(p.from)
183 } catch (e) {
184 throw format('Malformed "from" parameter in picture {0}.', i + 1);
185 }
186 try {
187 p.to = parse_position_param(p.to)
188 } catch (e) {
189 throw format('Malformed "to" parameter in picture {0}.', i + 1);
190 }
191 if (! p.time)
192 throw format('Missing "time" parameter in picture {0}.', i + 1);
193 p.time_ms = Math.round(p.time * 1000)
194 }
195
196 // precalculate left/top/width/height bounding values
197 if (p.from)
198 jQuery.each([ p.from, p.to ], function(i, from_to) {
199 from_to.width = Math.round(p.width * from_to.zoom);
200 from_to.height = Math.round(p.height * from_to.zoom);
201 from_to.left = Math.round((self_width - from_to.width) * from_to.xrel);
202 from_to.top = Math.round((self_height - from_to.height) * from_to.yrel);
203 });
204
205 // append the image element to the container
206 jQuery(format('<img src="{0}"/>', p.src)).appendTo(self).css({
207 position: 'absolute',
208 visibility: 'hidden'
209 });
210 }
211 speed = undefined; // speed mode has now been translated to full mode
212
213 var imgs = self.children();
214
215 // show first image
216 imgs.eq(0).css({ visibility: 'visible' });
217 if (! sleep)
218 imgs.eq(0).css(position_to_css(plan[0], 2));
219
220 // create animation chain
221 function create_chain(i, chainf) {
222 // building the chain backwards, or inside out
223
224 if (i % 2 == 0) {
225 if (sleep) {
226
227 // still image sleep
228
229 var i_sleep = i / 2,
230 i_hide = (i_sleep - 1 + plan.length) % plan.length,
231 img_sleep = imgs.eq(i_sleep),
232 img_hide = imgs.eq(i_hide);
233
234 var newf = function() {
235 img_hide.css('visibility', 'hidden');
236 setTimeout(chainf, sleep);
237 };
238
239 if (debug)
240 debug.prepend('<hr/>'
241 + format("img[{0}].css(visibility, hidden)\n", i_hide)
242 + format("setTimeout(&#9660;, {0})", sleep));
243
244 } else {
245
246 // single image slide
247
248 var i_slide = i / 2,
249 i_hide = (i_slide - 1 + plan.length) % plan.length,
250 img_slide = imgs.eq(i_slide),
251 img_hide = imgs.eq(i_hide),
252 time = plan[i_slide].time_ms,
253 slide_anim = position_to_css(plan[i_slide], 3);
254
255 var newf = function() {
256 img_hide.css('visibility', 'hidden');
257 img_slide.animate(slide_anim, time, 'linear', chainf);
258 };
259
260 if (debug)
261 debug.prepend('<hr/>'
262 + format("img[{0}].css(visibility, hidden)\n", i_hide)
263 + format("img[{0}].animate({1}, {2}, linear, &#9660;)", i_slide, dump_obj(slide_anim), time));
264
265 }
266 } else {
267 if (sleep) {
268
269 // still image cross-fade
270
271 var i_from = Math.floor(i / 2),
272 i_to = Math.ceil(i / 2) % plan.length,
273 img_from = imgs.eq(i_from),
274 img_to = imgs.eq(i_to),
275 from_anim = {},
276 to_init = { visibility: 'visible' },
277 to_anim = {};
278
279 if (i_to > i_from) {
280 to_init.opacity = 0;
281 to_anim.opacity = 1;
282 } else {
283 from_anim.opacity = 0;
284 }
285
286 var newf = function() {
287 img_to.css(to_init);
288 if (from_anim.opacity != undefined)
289 img_from.animate(from_anim, fade_ms, 'linear', chainf);
290 else
291 img_to.animate(to_anim, fade_ms, 'linear', chainf);
292 };
293
294 if (debug)
295 debug.prepend('<hr/>'
296 + format("img[{0}].css({1})\n", i_to, dump_obj(to_init))
297 + (from_anim.opacity != undefined
298 ? format("img[{0}].animate({1}, {2}, linear, &#9660;)", i_from, dump_obj(from_anim), fade_ms)
299 : format("img[{0}].animate({1}, {2}, linear, &#9660;)", i_to, dump_obj(to_anim), fade_ms)));
300
301 } else {
302
303 // cross-slide + cross-fade
304
305 var i_from = Math.floor(i / 2),
306 i_to = Math.ceil(i / 2) % plan.length,
307 img_from = imgs.eq(i_from),
308 img_to = imgs.eq(i_to),
309 from_anim = position_to_css(plan[i_from], 4),
310 to_init = position_to_css(plan[i_to], 1),
311 to_anim = position_to_css(plan[i_to], 2);
312
313 if (i_to > i_from) {
314 to_init.opacity = 0;
315 to_anim.opacity = 1;
316 } else {
317 from_anim.opacity = 0;
318 }
319 to_init.visibility = 'visible';
320
321 var newf = function() {
322 img_from.animate(from_anim, fade_ms, 'linear');
323 img_to.css(to_init);
324 img_to.animate(to_anim, fade_ms, 'linear', chainf);
325 };
326
327 if (debug)
328 debug.prepend('<hr/>'
329 + format("img[{0}].animate({1}, {2}, linear)\n", i_from, dump_obj(from_anim), fade_ms)
330 + format("img[{0}].css({1})\n", i_to, dump_obj(to_init))
331 + format("img[{0}].animate({1}, {2}, linear, &#9660;)", i_to, dump_obj(to_anim), fade_ms));
332
333 }
334 }
335 if (i > 0)
336 return create_chain(i - 1, newf);
337 else
338 return newf;
339 }
340 var animation = create_chain(plan.length * 2 - 1, function() { return animation(); });
341
342 // show debug window, if enabled
343 if (debug)
344 jQuery(window.open('', 'debug', 'width=600,height=500,menubar=no,toolbar=no,directories=no,'
345 + 'location=no,status=no,scrollbars=yes,resizable=yes').document.body)
346 .empty()
347 .append(debug);
348
349 // start animation
350 animation();
351
352 });
353
354 return self;
355 };

  ViewVC Help
Powered by ViewVC 1.1.2