-
Notifications
You must be signed in to change notification settings - Fork 190
/
jquery.collagePlus.js
401 lines (328 loc) · 14.8 KB
/
jquery.collagePlus.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
/*!
*
* jQuery collagePlus Plugin v0.3.3
* https://github.com/ed-lea/jquery-collagePlus
*
* Copyright 2012, Ed Lea twitter.com/ed_lea
*
* built for http://qiip.me
*
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://www.opensource.org/licenses/mit-license.php
* http://www.opensource.org/licenses/GPL-2.0
*
*/
;(function( $ ) {
$.fn.collagePlus = function( options ) {
return this.each(function() {
/*
*
* set up vars
*
*/
// track row width by adding images, padding and css borders etc
var row = 0,
// collect elements to be re-sized in current row
elements = [],
// track the number of rows generated
rownum = 1,
// needed for creating some additional defaults that are actually obtained
// from the dom, which maybe doesn't make them defaults ?!
$this = $(this);
// width of the area the collage will be in
$.fn.collagePlus.defaults.albumWidth = $this.width();
// padding between the images. Using padding left as we assume padding is even all the way round
$.fn.collagePlus.defaults.padding = parseFloat( $this.css('padding-left') );
// object that contains the images to collage
$.fn.collagePlus.defaults.images = $this.children();
var settings = $.extend({}, $.fn.collagePlus.defaults, options);
settings.images.each(
function(index){
/*
*
* Cache selector
* Even if first child is not an image the whole sizing is based on images
* so where we take measurements, we take them on the images
*
*/
var $this = $(this),
$img = ($this.is("img")) ? $this : $(this).find("img");
/*
*
* get the current image size. Get image size in this order
*
* 1. from <img> tag
* 2. from data set from initial calculation
* 3. after loading the image and checking it's actual size
*
*/
var w = (typeof $img.data("width") != 'undefined') ? $img.data("width") : $img.width(),
h = (typeof $img.data("height") != 'undefined') ? $img.data("height") : $img.height();
/*
*
* Get any current additional properties that may affect the width or height
* like css borders for example
*
*/
var imgParams = getImgProperty($img);
/*
*
* store the original size for resize events
*
*/
$img.data("width", w);
$img.data("height", h);
/*
*
* calculate the w/h based on target height
* this is our ideal size, but later we'll resize to make it fit
*
*/
var nw = Math.ceil(w/h*settings.targetHeight),
nh = Math.ceil(settings.targetHeight);
/*
*
* Keep track of which images are in our row so far
*
*/
elements.push([this, nw, nh, imgParams['w'], imgParams['h']]);
/*
*
* calculate the width of the element including extra properties
* like css borders
*
*/
row += nw + imgParams['w'] + settings.padding;
/*
*
* if the current row width is wider than the parent container
* it's time to make a row out of our images
*
*/
if( row > settings.albumWidth && elements.length != 0 ){
// call the method that calculates the final image sizes
// remove one set of padding as it's not needed for the last image in the row
resizeRow(elements, (row - settings.padding), settings, rownum);
// reset our row
delete row;
delete elements;
row = 0;
elements = [];
rownum += 1;
}
/*
*
* if the images left are not enough to make a row
* then we'll force them to make one anyway
*
*/
if ( settings.images.length-1 == index && elements.length != 0){
resizeRow(elements, row, settings, rownum);
// reset our row
delete row;
delete elements;
row = 0;
elements = [];
rownum += 1;
}
}
);
});
function resizeRow( obj, row, settings, rownum) {
/*
*
* How much bigger is this row than the available space?
* At this point we have adjusted the images height to fit our target height
* so the image size will already be different from the original.
* The resizing we're doing here is to adjust it to the album width.
*
* We also need to change the album width (basically available space) by
* the amount of padding and css borders for the images otherwise
* this will skew the result.
*
* This is because padding and borders remain at a fixed size and we only
* need to scale the images.
*
*/
var imageExtras = (settings.padding * (obj.length - 1)) + (obj.length * obj[0][3]),
albumWidthAdjusted = settings.albumWidth - imageExtras,
overPercent = albumWidthAdjusted / (row - imageExtras),
// start tracking our width with know values that will make up the total width
// like borders and padding
trackWidth = imageExtras,
// guess whether this is the last row in a set by checking if the width is less
// than the parent width.
lastRow = (row < settings.albumWidth ? true : false);
/*
* Resize the images by the above % so that they'll fit in the album space
*/
for (var i = 0; i < obj.length; i++) {
var $obj = $(obj[i][0]),
fw = Math.floor(obj[i][1] * overPercent),
fh = Math.floor(obj[i][2] * overPercent),
// if the element is the last in the row,
// don't apply right hand padding (this is our flag for later)
isNotLast = !!(( i < obj.length - 1 ));
/*
* Checking if the user wants to not stretch the images of the last row to fit the
* parent element size
*/
if(settings.allowPartialLastRow === true && lastRow === true){
fw = obj[i][1];
fh = obj[i][2];
}
/*
*
* Because we use % to calculate the widths, it's possible that they are
* a few pixels out in which case we need to track this and adjust the
* last image accordingly
*
*/
trackWidth += fw;
/*
*
* here we check if the combined images are exactly the width
* of the parent. If not then we add a few pixels on to make
* up the difference.
*
* This will alter the aspect ratio of the image slightly, but
* by a noticable amount.
*
* If the user doesn't want full width last row, we check for that here
*
*/
if(!isNotLast && trackWidth < settings.albumWidth){
if(settings.allowPartialLastRow === true && lastRow === true){
fw = fw;
}else{
fw = fw + (settings.albumWidth - trackWidth);
}
}
fw--;
/*
*
* We'll be doing a few things to the image so here we cache the image selector
*
*
*/
var $img = ( $obj.is("img") ) ? $obj : $obj.find("img");
/*
*
* Set the width of the image and parent element
* if the resized element is not an image, we apply it to the child image also
*
* We need to check if it's an image as the css borders are only measured on
* images. If the parent is a div, we need make the contained image smaller
* to accommodate the css image borders.
*
*/
$img.width(fw);
if( !$obj.is("img") ){
$obj.width(fw + obj[i][3]);
}
/*
*
* Set the height of the image
* if the resized element is not an image, we apply it to the child image also
*
*/
$img.height(fh);
if( !$obj.is("img") ){
$obj.height(fh + obj[i][4]);
}
/*
*
* Apply the css extras like padding
*
*/
applyModifications($obj, isNotLast, settings);
/*
*
* Assign the effect to show the image
* Default effect is using jquery and not CSS3 to support more browsers
* Wait until the image is loaded to do this
*
*/
$img
.one('load', function (target) {
return function(){
if( settings.effect == 'default'){
target.animate({opacity: '1'},{duration: settings.fadeSpeed});
} else {
if(settings.direction == 'vertical'){
var sequence = (rownum <= 10 ? rownum : 10);
} else {
var sequence = (i <= 9 ? i+1 : 10);
}
/* Remove old classes with the "effect-" name */
target.removeClass(function (index, css) {
return (css.match(/\beffect-\S+/g) || []).join(' ');
});
target.addClass(settings.effect);
target.addClass("effect-duration-" + sequence);
}
}
}($obj))
/*
* fix for cached or loaded images
* For example if images are loaded in a "window.load" call we need to trigger
* the load call again
*/
.each(function() {
if(this.complete) $(this).trigger('load');
});
}
}
/*
*
* This private function applies the required css to space the image gallery
* It applies it to the parent element so if an image is wrapped in a <div> then
* the css is applied to the <div>
*
*/
function applyModifications($obj, isNotLast, settings) {
var css = {
// Applying padding to element for the grid gap effect
'margin-bottom' : settings.padding + "px",
'margin-right' : (isNotLast) ? settings.padding + "px" : "0px",
// Set it to an inline-block by default so that it doesn't break the row
'display' : settings.display,
// Set vertical alignment otherwise you get 4px extra padding
'vertical-align' : "bottom",
// Hide the overflow to hide the caption
'overflow' : "hidden"
};
return $obj.css(css);
}
/*
*
* This private function calculates any extras like padding, border associated
* with the image that will impact on the width calculations
*
*/
function getImgProperty( img )
{
$img = $(img);
var params = new Array();
params["w"] = (parseFloat($img.css("border-left-width")) + parseFloat($img.css("border-right-width")));
params["h"] = (parseFloat($img.css("border-top-width")) + parseFloat($img.css("border-bottom-width")));
return params;
}
};
$.fn.collagePlus.defaults = {
// the ideal height you want your images to be
'targetHeight' : 400,
// how quickly you want images to fade in once ready can be in ms, "slow" or "fast"
'fadeSpeed' : "fast",
// how the resized block should be displayed. inline-block by default so that it doesn't break the row
'display' : "inline-block",
// which effect you want to use for revealing the images (note CSS3 browsers only),
'effect' : 'default',
// effect delays can either be applied per row to give the impression of descending appearance
// or horizontally, so more like a flock of birds changing direction
'direction' : 'vertical',
// Sometimes there is just one image on the last row and it gets blown up to a huge size to fit the
// parent div width. To stop this behaviour, set this to true
'allowPartialLastRow' : false
};
})( jQuery );