1/* 2 jQuery Mosaic v0.12 3 https://github.com/tin-cat/jquery-mosaic 4 A jquery plugin by Tin.cat to build beautifully arranged and responsive mosaics of html elements maintaining their original aspect ratio. Works wonderfully with images by creating a visually ordered and pleasant mosaic (much like mosaics on Flickr, 500px and Google+) without gaps between elements, but at the same time respecting aspect ratios. Reacts to window resizes and adapts responsively to any screen size. See it working on https://skinography.net 5 */ 6 7(function($){ 8 9 $.Mosaic = function(el, options) { 10 var base = this, o; 11 base.el = el; 12 base.$el = $(el); 13 14 base.$el.data('Mosaic', base); 15 16 var baseWidth; 17 var refitTimeout = false; 18 19 base.init = function() { 20 base.options = o = $.extend({}, $.Mosaic.defaults, options); 21 22 $(base.el).addClass("mosaic"); 23 24 if (o.outerMargin) 25 $(base.el).css('padding', o.outerMargin); 26 27 if (o.innerGap) 28 $(base.el).css('margin-bottom', o.innerGap * -1); 29 30 base.fit(); 31 32 if (o.refitOnResize) 33 $(window).on('resize', null, null, function() { 34 if (o.refitOnResizeDelay) { 35 if (refitTimeout) 36 clearTimeout(refitTimeout); 37 refitTimeout = setTimeout(function() { 38 base.fit() 39 }, o.refitOnResizeDelay); 40 } 41 else 42 base.fit() 43 }); 44 } 45 46 base.getItems = function() { 47 return $('> div:not([data-no-mosaic=true]), > a:not([data-no-mosaic=true]), > img:not([data-no-mosaic=true]), > li:not([data-no-mosaic=true])', base.el); 48 } 49 50 base.getItemAtIndex = function(index) { 51 if (!base.getItems()[index]) 52 return false; 53 return $(base.getItems()[index]); 54 } 55 56 base.getItemsSubset = function(start, numberOf) { 57 var items = base.getItems(); 58 if (start > items.length) 59 return false; 60 if (start + numberOf > items.length) 61 numberOf = items.length - start; 62 return items.slice(start, start + numberOf); 63 } 64 65 base.isLastItemsSubset = function(start, numberOf) { 66 var items = base.getItems(); 67 if (start > items.length) 68 return true; 69 if (start + numberOf > items.length) 70 return true; 71 return false; 72 } 73 74 base.getItemWidth = function(item) { 75 return $(item).attr('width'); 76 } 77 78 base.getItemHeight = function(item) { 79 return $(item).attr('height'); 80 } 81 82 base.getItemAspectRatio = function(item) { 83 if ($(item).data('aspect-ratio')) 84 return $(item).data('aspect-ratio'); 85 if (base.getItemWidth(item) && base.getItemHeight(item)) 86 return base.getItemWidth(item) / base.getItemHeight(item); 87 return o.defaultAspectRatio; 88 } 89 90 base.getItemWidthForGivenHeight = function(item, height) { 91 return height * base.getItemAspectRatio(item); 92 } 93 94 base.getItemHeightForGivenWidth = function(item, width) { 95 return width / base.getItemAspectRatio(item); 96 } 97 98 base.setItemSizeByGivenHeight = function(item, height) { 99 var width = Math.floor(base.getItemWidthForGivenHeight(item, height)); 100 $(item) 101 .css('height', Math.floor(height)) 102 .css('width', width); 103 104 if (o.highResImagesWidthThreshold) { 105 106 if (width > o.highResImagesWidthThreshold) { 107 108 var highResBackgroundImage = $(item).data('high-res-background-image-url'); 109 if ( 110 highResBackgroundImage 111 && 112 !$(item).data('low-res-background-image-url') 113 ) { 114 $(item).data('low-res-background-image-url', $(item).css('background-image')); 115 $(item).css('background-image', 'url("' + highResBackgroun
115dImage + '")'); 116 $(item).addClass('highRes'); 117 } 118 119 var highResImage = $(item).data('high-res-image-src'); 120 if ( 121 highResImage 122 && 123 !$(item).data('low-res-image-src') 124 ) { 125 $(item).data('low-res-image-src', $(item).attr('src')); 126 $(item).attr('src', highResImage); 127 $(item).addClass('highRes'); 128 } 129 } 130 else { 131 132 var lowResBackgroundImage = $(item).data('low-res-background-image-url'); 133 if (lowResBackgroundImage) { 134 $(item).css('background-image', lowResBackgroundImage); 135 $(item).data('low-res-background-image-url', false); 136 $(item).removeClass('highRes'); 137 } 138 139 var lowResImage = $(item).data('low-res-image-src'); 140 if (lowResImage) { 141 $(item).attr('src', lowResImage); 142 $(item).data('low-res-image-src', false); 143 $(item).removeClass('highRes'); 144 } 145 146 } 147 148 } 149 150 return width; 151 } 152 153 base.calculateHeightToFit = function(items) { 154 var sumAspectRatios = 0; 155 items.each(function() { 156 sumAspectRatios += parseFloat(base.getItemAspectRatio(this)); 157 }); 158 return (baseWidth - (o.innerGap * (items.length - 1))) / sumAspectRatios; 159 } 160 161 base.retrieveBaseWidth = function() { 162 baseWidth = $(base.el).width(); 163 } 164 165 base.fit = function() { 166 base.retrieveBaseWidth(); 167 168 var items, height; 169 var itemsToUse = 1; 170 var startIndex = 0; 171 var isAnyFitted = false; 172 while (true) { 173 174 items = base.getItemsSubset(startIndex, itemsToUse); 175 176 if (base.isLastItemsSubset(startIndex, itemsToUse)) { 177 if (items.length) { 178 base.fitItems(items); 179 } 180 break; 181 } 182 183 height = base.calculateHeightToFit(items); 184 185 if (height > o.maxRowHeight) { 186 itemsToUse ++; 187 continue; 188 } 189 190 base.fitItems(items); 191 startIndex += itemsToUse; 192 itemsToUse = 1; 193 isAnyFitted = true; 194 } 195 196 // If maxRowHeight has not been met at any point (might happen when specifying short maxRowHeights) 197 if (!isAnyFitted) 198 base.fitItems(base.getItems()); 199 } 200 201 base.fitItems = function(items) { 202 var height = base.calculateHeightToFit(items); 203 if (height > o.maxRowHeight) { 204 switch (o.maxRowHeightPolicy) { 205 case 'skip': 206 items.each(function() { $(this).hide(); }); 207 return; 208 break; 209 case 'crop': 210 height = o.maxRowHeight; 211 break; 212 case 'oversize': 213 // Do nothing 214 break; 215 } 216 } 217 items.each(function() { $(this).show(); }); 218 var accumulatedWidth = 0; 219 items.each(function(idx) { 220 accumulatedWidth += base.setItemSizeByGivenHeight(this, height); 221 if (o.innerGap) { 222 $(this).css('margin-right', idx < items.length - 1 ? o.innerGap : 0); 223 $(this).css('margin-bottom', o.innerGap); 224 } 225 }); 226 // Enlarge a bit the last element to compensate for accumulated floored decimal widths leaving a gap at the end 227 if (accumulatedWidth < baseWidth)
228 items.last().css('width', 229 items.last().width() + ((baseWidth - ((items.width - 1) * o.innerGap) ) - accumulatedWidth) 230 ); 231 } 232 233 base.init(); 234 } 235 236 $.Mosaic.defaults = { 237 maxRowHeight: 400, // The maximum desired height of rows 238 refitOnResize: true, // Whether to rebuild the mosaic when the window is resized or not 239 refitOnResizeDelay: false, // Milliseconds to wait after a resize event to refit the mosaic. Useful when creating huge mosaics that can take some CPU time on the user's browser. Leave it to false to refit the mosaic in realtime. 240 defaultAspectRatio: 1, // The aspect ratio to use when none has been specified, or can't be calculated 241 maxRowHeightPolicy: 'skip', // Sometimes some of the remaining items cannot be fitted on a row without surpassing the maxRowHeight. For those cases, choose one of the available settings for maxRowHeightPolicy: "skip": Does not renders the unfitting items. "crop": caps the desired height to the specified maxRowHeight, resulting in those items not keeping their aspect ratios. "oversize": Renders the items respecting their aspect ratio but surpassing the specified maxRowHeight 242 highResImagesWidthThreshold: 350, // The item width on which to start using the the provided high resolution image instead of the normal one. High resolution images are specified via the "data-high-res-image-src" or "data-high-res-background-image-url" html element properties of each item. 243 outerMargin: 0, // A margin size in pixels for the outher edge of the whole mosaic 244 innerGap: 0 // A gap size in pixels to leave a space between elements 245 }; 246 247 $.fn.Mosaic = function(options, params) { 248 return this.each(function(){ 249 var me = $(this).data('Mosaic'); 250 if ((typeof(options)).match('object|undefined')) 251 new $.Mosaic(this, options); 252 else 253 eval('me.'+options)(params); 254 }); 255 } 256 257})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.