PageSourceSearch

https://graviton.com.ar/js/jquery.isotope.perfectmasonry.js

js graviton.com.ar collected 2026-10-05 06:15:23 UTC 10,629 bytes, 278 lines download raw bytes

1/*!
2 * PerfectMasonry extension for Isotope
3 *
4 * Does similar things as the Isotopes "masonry" layoutmode, except that this one will actually go back and plug the holes
5 * left by bigger elements, thus making a perfect brick wall. Profit!
6 * 
7 * Usage:
8 * 	$('#grid').isotope({
9 * 		layoutMode: 'perfectMasonry',
10 *		perfectMasonry: {
11 *			layout: 'horizontal',		// Set layout as vertical/horizontal (default: vertical)
12 *			columnWidth: 200,			// Set/Prefer columns to x wide (default: width of first tile)
13 *			rowHeight: 200,				// Set/Prefer rows to y high (default: height of first tile)
14 * 
15 *			liquid: true,				// Set layout as liquid (default: false)
16 *			cols: 3,					// Force to have x columns (default: null)
17 *			rows: 3,					// Force to have y rows (default: null)
18 *			minCols: 3,					// Set min col count (default: 1)
19 *			minRows: 3,					// Set min row count (default: 1)
20 *			maxCols: 5,					// Set max col count (default: 9999)
21 *			maxRows: 4					// Set max row count (default: 9999)
22 * 		}
23 * 	});
24 *
25 * 
26 * @author Mikko Tikkanen, Zonear Ltd. <[email protected]>
27 */
28;(function($, undefined) {
29	var version = '1.2.1';
30	var isotope = null,
31		$context = null,
32		$container = null;
33	
34	$.extend($.Isotope.prototype, {
35		isFirstRun: true,
36
37		/**
38		 * Reset layout properties
39		 *
40		 * Runs before any layout change
41		 * -------------------------------------------------------------------------------------------------------- */
42		_perfectMasonryReset: function() {
43			this.options.perfectMasonry = this.options.perfectMasonry|| {};
44			var isVertical = this.options.perfectMasonry.layout != 'horizontal',
45				isLiquid = this.options.perfectMasonry.liquid == true;
46			
47			// Do things on a first run
48			if(this.isFirstRun) {
49				this.isFirstRun = false;
50				isotope = this;
51				$context = $(this.element.context);
52				$container = $context.parent();
53				
54				// Make sure we have min/maxCols & rows
55				this.options.perfectMasonry.minCols = this.options.perfectMasonry.minCols || 1; 
56				this.options.perfectMasonry.minRows = this.options.perfectMasonry.minRows || 1;
57				this.options.perfectMasonry.maxCols = this.options.perfectMasonry.maxCols || 9999; 
58				this.options.perfectMasonry.maxRows = this.options.perfectMasonry.maxRows || 9999;
59			}
60			
61			// For liquid layout, replace default resize handler with forced relayout (outside firstRun as Isotope grid can be destroyed and created on the fly)
62			if(isLiquid && $.data(window, 'events') && $._data(window, 'events').smartresize) {
63				$(window).off('smartresize.isotope');
64				$(window).on('resize.isotope.perfectmasonry', function() {
65					if(!$context.hasClass('isotope')) { return; }
66					$context.isotope('reLayout');
67				});
68			}
69			
70			// Setup layout properties ---------------------------------------------------
71			var properties = this.perfectMasonry = {};
72			
73			// Fill properties with columnWidth and rowHeight (true argument)
74			this._getSegments();
75      		this._getSegments(true);
76      		
77      		// ...and with cols & rows
78			this._perfectMasonryGetSegments();
79      		
80			// Handle liquid layout (cols, rows & sizes must be calculated on the fly)
81			if(isLiquid) {
82				var width = $container.width(),
83					height = $container.height();
84					
85				// Make sure we have colwidth & rowheight (get it from the calculated )
86				this.options.perfectMasonry.columnWidth = this.options.perfectMasonry.columnWidth || properties.columnWidth;
87				this.options.perfectMasonry.rowHeight = this.options.perfectMasonry.rowHeight || properties.rowHeight;
88				
89				// Figure out how many cols & rows either have been set or can be fit into the container (also make sure we're still between min/max)
90				properties.cols = this.options.perfectMasonry.cols || Math.floor(width / this.options.perfectMasonry.columnWidth);
91				properties.rows = this.options.perfectMasonry.rows || Math.floor(height / this.options.perfectMasonry.rowHeight);
92				properties.cols = Math.min(Math.max(properties.cols, this.options.perfectMasonry.minCols), this.options.perfectMasonry.maxCols);
93				properties.rows = Math.min(Math.max(properties.rows, this.options.perfectMasonry.minRows), this.options.perfectMasonry.maxRows);
94								
95				// Recalculate accurate width/height so that the whole available space is used
96				var diff = (isVertical ? properties.columnWidth / (width / properties.cols) : properties.rowHeight / (height / properties.rows));
97				properties.columnWidth = Math.floor(properties.columnWidth / diff);
98				properties.rowHeight = Math.floor(properties.rowHeight / diff);
99			}
100			
101			// Create top row of the grid
102			properties.grid = new Array(this.perfectMasonry.cols);
103
104			// Set container dimensions to 0
105			properties.containerHeight = 0;
106			properties.containerWidth = 0;
107	    },
108
109
110
111	    /**
112		 * Create layout
113		 * -------------------------------------------------------------------------------------------------------- */
114		_perfectMasonryLayout: function($elems) {
115			var instance = this,
116				properties = this.perfectMasonry,
117				isVertical = instance.options.perfectMasonry.layout != 'horizontal',
118				isLiquid = instance.options.perfectMasonry.liquid == true;
119			
120			// Create first set of the grid
121			properties.grid = new Array(properties[(isVertical ? 'cols' : 'rows')]);
122			if(!properties.grid || !properties.grid.length) { return; }
123			
124			// Loop each element
125			$elems.each(function() {
126				var $this  = $(this);
127				
128				// Calculate col & row spans (with liquid layouts, store desired width as element data)
129				var colSpan = (isLiquid ? $this.data('colSpan') : Math.ceil($this.outerWidth() / (properties.columnWidth + 1))),
130					rowSpan = (isLiquid ? $this.data('rowSpan') : Math.ceil($this.outerHeight() / (properties.rowHeight + 1)));
131				
132				// For the first run with liquid layout, calculate sizes
133				if(!colSpan) {
134					colSpan = Math.ceil($this.outerWidth(true) / (properties.columnWidth + 1));
135					rowSpan = Math.ceil($this.outerHeight(true) / (properties.rowHeight + 1));
136					$this.data('colSpan', colSpan);
137					$this.data('rowSpan', rowSpan);
138				}
139				
140				
141				/* Do the layout
142				 * -------------------------------------------------------------------------------- */
143				
144				// Set spans
145				var aSpan = (isVertical ? colSpan : rowSpan);
146				var bSpan = (isVertical ? rowSpan : colSpan);
147				
148				// Bigger tiles can't fit into the last primary (though keep it still at least as 1)
149				var max = Math.max((isVertical ? properties.cols - colSpan : properties.rows - rowSpan) + 1, 1);
150								
151				// Loop through/create primaries (set hard limit of 10.000 to prevent endless loop)
152				var a = -1, x = 0, y = 0;
153				while(++a < 10000) {
154					properties.grid[a] = properties.grid[a] || [];
155					
156					// Go through the secondaries in the primary, set secondary and tile
157					for (var b = 0; b < max; b++) {
158						var tile = properties.grid[a][b];
159							
160						// If the tile is not free, move to the next one immediately
161						if(tile) { continue; }
162
163						// Tiles spanning to multiple rows/columns - Check if it'll fit
164						var doesFit = true;
165						if(colSpan > 1 || rowSpan > 1) {
166							for (var i = 0; i < aSpan; i++) {
167								for (var j = 0; j < bSpan; j++) {
168									properties.grid[a+j] = properties.grid[a+j] || [];
169									if(properties.grid[a+j][b+i]) { doesFit = false; break; }
170								}
171
172								// If it doesn't fit, don't waste our time looping
173								if(!doesFit) { break; }
174							}
175						}
176						if(!doesFit) { continue }
177						
178
179						// Set all the cells as occupied
180						for (var i = 0; i < aSpan; i++) {
181							for (var j = 0; j < bSpan; j++) {
182								properties.grid[a+j][b+i] = true;
183							}
184						}
185						
186						// Set x & y values
187						var x = a, y = b;
188						if(isVertical) { var x = b, y = a; }
189						
190						// Update container dimensions
191						properties.containerWidth = Math.max(properties.containerWidth, (x + aSpan) * properties.columnWidth);
192						properties.containerHeight = Math.max(properties.containerHeight, (y + bSpan) * properties.rowHeight);
193						
194						// In case of liquid layout, set element size full width/height
195						if(instance.options.perfectMasonry.liquid == true) {
196							$this.css({
197								width: properties.columnWidth * colSpan,
198								height: properties.rowHeight * rowSpan
199							});
200						}
201
202						// Set the element location and GTFO
203						instance._pushPosition($this, x*properties.columnWidth, y*properties.rowHeight);
204						return;
205					}
206				}
207				
208
209				// If we got all the way down to here, the element doesn't fit - Hide it
210				instance._pushPosition($this, -9999, -9999);
211			});
212			
213			// Set row & column count to container
214			var rows = (isVertical ? properties.grid.length : properties.grid[0] && properties.grid[0].length),
215				cols = (isVertical ? properties.grid[0] && properties.grid[0].length : properties.grid.length);
216			$(this.element.context).attr('data-isotope-rows', rows).attr('data-isotope-cols', cols);
217		},
218		
219		
220		
221	    /**
222		 * Get container size
223		 *
224		 * For resizing the container
225		 * -------------------------------------------------------------------------------------------------------- */
226	    _perfectMasonryGetContainerSize: function() {
227			return {
228				width: this.perfectMasonry.containerWidth,
229				height: this.perfectMasonry.containerHeight
230			};
231	    },
232		
233		
234		
235	    /**
236		 * Resize changed
237		 *
238		 * Figure out if layout changed
239		 * -------------------------------------------------------------------------------------------------------- */
240	    _perfectMasonryResizeChanged: function() {
241	    	var properties = this.perfectMasonry;
242
243	    	// Store old values and calculate new numbers
244	    	var oldCols = properties.cols,
245	    		oldRows = properties.rows;
246	    	this._perfectMasonryGetSegments();
247			
248			// If new count was different, force layout change
249			if(this.options.perfectMasonry.layout == 'horizontal' && oldRows !== properties.rows) { return true; }
250			if(oldCols !== properties.cols) { return true; }
251			
252	    	return false;
253	    },
254		
255		
256		
257		
258	    /**
259		 * Private
260		 * Do segment calculations by hand
261		 * -------------------------------------------------------------------------------------------------------- */
262		_perfectMasonryGetSegments: function() {
263			var properties = this.perfectMasonry;
264			var parent = this.options.perfectMasonry.parent || this.element.parent();
265			
266			// Calculate columns
267			var parentWidth = parent.width();
268			properties.cols = Math.floor(parentWidth / properties.columnWidth) || 1;
269
270			// Calculate rows
271			var parentHeight = parent.height();
272			properties.rows = Math.floor(parentHeight / properties.rowHeight) || 1;
273		}
274	});
275	
276	
277})(jQuery);
278

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.