1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | ( function( window, factory ) {
|
10 |
|
11 |
|
12 | if ( typeof define == 'function' && define.amd ) {
|
13 |
|
14 | define( [
|
15 | 'outlayer/outlayer',
|
16 | 'get-size/get-size'
|
17 | ],
|
18 | factory );
|
19 | } else if ( typeof module == 'object' && module.exports ) {
|
20 |
|
21 | module.exports = factory(
|
22 | require('outlayer'),
|
23 | require('get-size')
|
24 | );
|
25 | } else {
|
26 |
|
27 | window.Masonry = factory(
|
28 | window.Outlayer,
|
29 | window.getSize
|
30 | );
|
31 | }
|
32 |
|
33 | }( window, function factory( Outlayer, getSize ) {
|
34 |
|
35 | 'use strict';
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | var Masonry = Outlayer.create('masonry');
|
41 |
|
42 | Masonry.compatOptions.fitWidth = 'isFitWidth';
|
43 |
|
44 | var proto = Masonry.prototype;
|
45 |
|
46 | proto._resetLayout = function() {
|
47 | this.getSize();
|
48 | this._getMeasurement( 'columnWidth', 'outerWidth' );
|
49 | this._getMeasurement( 'gutter', 'outerWidth' );
|
50 | this.measureColumns();
|
51 |
|
52 |
|
53 | this.colYs = [];
|
54 | for ( var i=0; i < this.cols; i++ ) {
|
55 | this.colYs.push( 0 );
|
56 | }
|
57 |
|
58 | this.maxY = 0;
|
59 | this.horizontalColIndex = 0;
|
60 | };
|
61 |
|
62 | proto.measureColumns = function() {
|
63 | this.getContainerWidth();
|
64 |
|
65 | if ( !this.columnWidth ) {
|
66 | var firstItem = this.items[0];
|
67 | var firstItemElem = firstItem && firstItem.element;
|
68 |
|
69 | this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
|
70 |
|
71 | this.containerWidth;
|
72 | }
|
73 |
|
74 | var columnWidth = this.columnWidth += this.gutter;
|
75 |
|
76 |
|
77 | var containerWidth = this.containerWidth + this.gutter;
|
78 | var cols = containerWidth / columnWidth;
|
79 |
|
80 | var excess = columnWidth - containerWidth % columnWidth;
|
81 |
|
82 | var mathMethod = excess && excess < 1 ? 'round' : 'floor';
|
83 | cols = Math[ mathMethod ]( cols );
|
84 | this.cols = Math.max( cols, 1 );
|
85 | };
|
86 |
|
87 | proto.getContainerWidth = function() {
|
88 |
|
89 | var isFitWidth = this._getOption('fitWidth');
|
90 | var container = isFitWidth ? this.element.parentNode : this.element;
|
91 |
|
92 |
|
93 | var size = getSize( container );
|
94 | this.containerWidth = size && size.innerWidth;
|
95 | };
|
96 |
|
97 | proto._getItemLayoutPosition = function( item ) {
|
98 | item.getSize();
|
99 |
|
100 | var remainder = item.size.outerWidth % this.columnWidth;
|
101 | var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
|
102 |
|
103 | var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
|
104 | colSpan = Math.min( colSpan, this.cols );
|
105 |
|
106 | var colPosMethod = this.options.horizontalOrder ?
|
107 | '_getHorizontalColPosition' : '_getTopColPosition';
|
108 | var colPosition = this[ colPosMethod ]( colSpan, item );
|
109 |
|
110 | var position = {
|
111 | x: this.columnWidth * colPosition.col,
|
112 | y: colPosition.y
|
113 | };
|
114 |
|
115 | var setHeight = colPosition.y + item.size.outerHeight;
|
116 | var setMax = colSpan + colPosition.col;
|
117 | for ( var i = colPosition.col; i < setMax; i++ ) {
|
118 | this.colYs[i] = setHeight;
|
119 | }
|
120 |
|
121 | return position;
|
122 | };
|
123 |
|
124 | proto._getTopColPosition = function( colSpan ) {
|
125 | var colGroup = this._getTopColGroup( colSpan );
|
126 |
|
127 | var minimumY = Math.min.apply( Math, colGroup );
|
128 |
|
129 | return {
|
130 | col: colGroup.indexOf( minimumY ),
|
131 | y: minimumY,
|
132 | };
|
133 | };
|
134 |
|
135 | |
136 |
|
137 |
|
138 |
|
139 | proto._getTopColGroup = function( colSpan ) {
|
140 | if ( colSpan < 2 ) {
|
141 |
|
142 | return this.colYs;
|
143 | }
|
144 |
|
145 | var colGroup = [];
|
146 |
|
147 | var groupCount = this.cols + 1 - colSpan;
|
148 |
|
149 | for ( var i = 0; i < groupCount; i++ ) {
|
150 | colGroup[i] = this._getColGroupY( i, colSpan );
|
151 | }
|
152 | return colGroup;
|
153 | };
|
154 |
|
155 | proto._getColGroupY = function( col, colSpan ) {
|
156 | if ( colSpan < 2 ) {
|
157 | return this.colYs[ col ];
|
158 | }
|
159 |
|
160 | var groupColYs = this.colYs.slice( col, col + colSpan );
|
161 |
|
162 | return Math.max.apply( Math, groupColYs );
|
163 | };
|
164 |
|
165 |
|
166 | proto._getHorizontalColPosition = function( colSpan, item ) {
|
167 | var col = this.horizontalColIndex % this.cols;
|
168 | var isOver = colSpan > 1 && col + colSpan > this.cols;
|
169 |
|
170 | col = isOver ? 0 : col;
|
171 |
|
172 | var hasSize = item.size.outerWidth && item.size.outerHeight;
|
173 | this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
|
174 |
|
175 | return {
|
176 | col: col,
|
177 | y: this._getColGroupY( col, colSpan ),
|
178 | };
|
179 | };
|
180 |
|
181 | proto._manageStamp = function( stamp ) {
|
182 | var stampSize = getSize( stamp );
|
183 | var offset = this._getElementOffset( stamp );
|
184 |
|
185 | var isOriginLeft = this._getOption('originLeft');
|
186 | var firstX = isOriginLeft ? offset.left : offset.right;
|
187 | var lastX = firstX + stampSize.outerWidth;
|
188 | var firstCol = Math.floor( firstX / this.columnWidth );
|
189 | firstCol = Math.max( 0, firstCol );
|
190 | var lastCol = Math.floor( lastX / this.columnWidth );
|
191 |
|
192 | lastCol -= lastX % this.columnWidth ? 0 : 1;
|
193 | lastCol = Math.min( this.cols - 1, lastCol );
|
194 |
|
195 |
|
196 | var isOriginTop = this._getOption('originTop');
|
197 | var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
|
198 | stampSize.outerHeight;
|
199 | for ( var i = firstCol; i <= lastCol; i++ ) {
|
200 | this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
|
201 | }
|
202 | };
|
203 |
|
204 | proto._getContainerSize = function() {
|
205 | this.maxY = Math.max.apply( Math, this.colYs );
|
206 | var size = {
|
207 | height: this.maxY
|
208 | };
|
209 |
|
210 | if ( this._getOption('fitWidth') ) {
|
211 | size.width = this._getContainerFitWidth();
|
212 | }
|
213 |
|
214 | return size;
|
215 | };
|
216 |
|
217 | proto._getContainerFitWidth = function() {
|
218 | var unusedCols = 0;
|
219 |
|
220 | var i = this.cols;
|
221 | while ( --i ) {
|
222 | if ( this.colYs[i] !== 0 ) {
|
223 | break;
|
224 | }
|
225 | unusedCols++;
|
226 | }
|
227 |
|
228 | return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
|
229 | };
|
230 |
|
231 | proto.needsResizeLayout = function() {
|
232 | var previousWidth = this.containerWidth;
|
233 | this.getContainerWidth();
|
234 | return previousWidth != this.containerWidth;
|
235 | };
|
236 |
|
237 | return Masonry;
|
238 |
|
239 | }));
|