forked from zonear/isotope-perfectmasonry
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjquery.isotope.perfectmasonry.js
190 lines (139 loc) · 5.33 KB
/
jquery.isotope.perfectmasonry.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
/*!
* PerfectMasonry extension for Isotope
*
* Does similar things as the Isotopes "masonry" layoutmode, except that this one will actually go back and plug the holes
* left by bigger elements, thus making a perfect brick wall. Profit!
*
*
* @author Mikko Tikkanen, Zonear Ltd. <[email protected]>
*/
;(function($, undefined) {
$.extend($.Isotope.prototype, {
/**
* Reset layout properties
*
* Runs before any layout change
* -------------------------------------------------------------------------------------------------------- */
_perfectMasonryReset: function() {
// Setup layout properties
var properties = this.perfectMasonry = {};
// Get columnWidth & cols and rowHeight & rows (true argument) to properties
this._getSegments();
this._getSegments(true);
// Calculate cols & rows
this._perfectMasonryGetSegments();
// Create top row of the grid
properties.grid = new Array(this.perfectMasonry.cols);
// Set container dimensions to 0
properties.containerHeight = 0;
properties.containerWidth = 0;
},
/**
* Create layout
* -------------------------------------------------------------------------------------------------------- */
_perfectMasonryLayout: function($elems) {
var instance = this,
properties = this.perfectMasonry;
// Loop each element
$elems.each(function() {
var $this = $(this);
// Element width & height
var width = $this.outerWidth(true),
height = $this.outerHeight(true),
// How many columns/rows does the tile span
colSpan = Math.ceil(width / properties.columnWidth),
rowSpan = Math.ceil(height / properties.rowHeight);
// Wider tiles can't fit into the last column (though keep it still at least one column wide)
var maxCol = Math.max(properties.cols + 1 - colSpan, 1);
// Loop through rows
var y = -1;
while(true) {
y++;
// Add new rows as we go
properties.grid[y] = properties.grid[y] || [];
// Go through the cells in the row (columns)
for (var x = 0; x < maxCol; x++) {
// Does the tile fit here or not
var doesFit = true;
// If the tile is not free, move to the next one immediately
var tile = properties.grid[y][x];
if(tile) { continue; }
// Tiles spanning to multiple rows/columns - Check if it'll fit
if(colSpan > 1 || rowSpan > 1) {
for (var i = 0; i < rowSpan; i++) {
for (var j = 0; j < colSpan; j++) {
// If the row below is empty (undefined), we're alright
if(!properties.grid[y+i]) { continue; }
// Check if the cell is occupied - If yes, set doesFit to false and break
if(properties.grid[y+i][x+j]) { doesFit = false; break; }
}
// If it doesn't fit, don't waste our time here
if(!doesFit) { break; }
}
}
// If the shoe fits...
if(doesFit) {
// Fill the cells (handle elements that span multiple rows & columns)
for (var i = 0; i < rowSpan; i++) {
for (var j = 0; j < colSpan; j++) {
// Make sure the rows below current row are there
properties.grid[y+i] = properties.grid[y+i] || [];
// Set the item into the cell
properties.grid[y+i][x+j] = true;
}
}
// Update container dimensions
var newWidth = x * properties.columnWidth + width;
if(newWidth > properties.containerWidth) { properties.containerWidth = newWidth; }
var newHeight = y * properties.rowHeight + height;
if(newHeight > properties.containerHeight) { properties.containerHeight = newHeight; }
// Push element into the document and GTFO
instance._pushPosition($this, x*properties.columnWidth, y*properties.rowHeight);
return;
}
}
}
// If we got all the way down to here, the element doesn't fit - Hide it
instance._pushPosition($this, -9999, -9999);
});
},
/**
* Get container size
*
* For resizing the container
* -------------------------------------------------------------------------------------------------------- */
_perfectMasonryGetContainerSize: function() {
return {
width: this.perfectMasonry.containerWidth,
height: this.perfectMasonry.containerHeight
};
},
/**
* Resize changed
*
* Figure out if layout changed
* -------------------------------------------------------------------------------------------------------- */
_perfectMasonryResizeChanged: function() {
var properties = this.perfectMasonry;
// Store old col count and calculate new numbers
var oldCols = properties.cols;
this._perfectMasonryGetSegments();
// If new count was different, force layout change
if(oldCols !== properties.cols) { return true; }
return false;
},
/**
* Private
* Do segment calculations by hand
* -------------------------------------------------------------------------------------------------------- */
_perfectMasonryGetSegments: function() {
var properties = this.perfectMasonry;
// Calculate columns
var parentWidth = this.element.parent().width();
properties.cols = Math.floor(parentWidth / properties.columnWidth) || 1;
// Calculate rows
var parentHeight = this.element.parent().height();
properties.rows = Math.floor(parentHeight / properties.rowHeight) || 1;
}
});
})(jQuery);