0byt3m1n1
Path:
/
home
/
kassiope
/
OLD
/
assets
/
lib
/
packery
/
js
/
[
Home
]
File: packery.js
/*! * Packery v1.4.2 * bin-packing layout library * * Licensed GPLv3 for open source use * or Flickity Commercial License for commercial use * * http://packery.metafizzy.co * Copyright 2015 Metafizzy */ ( function( window, factory ) { 'use strict'; // universal module definition if ( typeof define == 'function' && define.amd ) { // AMD define( [ 'classie/classie', 'get-size/get-size', 'outlayer/outlayer', './rect', './packer', './item' ], factory ); } else if ( typeof exports == 'object' ) { // CommonJS module.exports = factory( require('desandro-classie'), require('get-size'), require('outlayer'), require('./rect'), require('./packer'), require('./item') ); } else { // browser global window.Packery = factory( window.classie, window.getSize, window.Outlayer, window.Packery.Rect, window.Packery.Packer, window.Packery.Item ); } }( window, function factory( classie, getSize, Outlayer, Rect, Packer, Item ) { 'use strict'; // ----- Rect ----- // // allow for pixel rounding errors IE8-IE11 & Firefox; #227 Rect.prototype.canFit = function( rect ) { return this.width >= rect.width - 1 && this.height >= rect.height - 1; }; // -------------------------- Packery -------------------------- // // create an Outlayer layout class var Packery = Outlayer.create('packery'); Packery.Item = Item; Packery.prototype._create = function() { // call super Outlayer.prototype._create.call( this ); // initial properties this.packer = new Packer(); // Left over from v1.0 this.stamp( this.options.stamped ); // create drag handlers var _this = this; this.handleDraggabilly = { dragStart: function() { _this.itemDragStart( this.element ); }, dragMove: function() { _this.itemDragMove( this.element, this.position.x, this.position.y ); }, dragEnd: function() { _this.itemDragEnd( this.element ); } }; this.handleUIDraggable = { start: function handleUIDraggableStart( event, ui ) { // HTML5 may trigger dragstart, dismiss HTML5 dragging if ( !ui ) { return; } _this.itemDragStart( event.currentTarget ); }, drag: function handleUIDraggableDrag( event, ui ) { if ( !ui ) { return; } _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); }, stop: function handleUIDraggableStop( event, ui ) { if ( !ui ) { return; } _this.itemDragEnd( event.currentTarget ); } }; }; // ----- init & layout ----- // /** * logic before any new layout */ Packery.prototype._resetLayout = function() { this.getSize(); this._getMeasurements(); // reset packer var packer = this.packer; // packer settings, if horizontal or vertical if ( this.options.isHorizontal ) { packer.width = Number.POSITIVE_INFINITY; packer.height = this.size.innerHeight + this.gutter; packer.sortDirection = 'rightwardTopToBottom'; } else { packer.width = this.size.innerWidth + this.gutter; packer.height = Number.POSITIVE_INFINITY; packer.sortDirection = 'downwardLeftToRight'; } packer.reset(); // layout this.maxY = 0; this.maxX = 0; }; /** * update columnWidth, rowHeight, & gutter * @private */ Packery.prototype._getMeasurements = function() { this._getMeasurement( 'columnWidth', 'width' ); this._getMeasurement( 'rowHeight', 'height' ); this._getMeasurement( 'gutter', 'width' ); }; Packery.prototype._getItemLayoutPosition = function( item ) { this._packItem( item ); return item.rect; }; /** * layout item in packer * @param {Packery.Item} item */ Packery.prototype._packItem = function( item ) { this._setRectSize( item.element, item.rect ); // pack the rect in the packer this.packer.pack( item.rect ); this._setMaxXY( item.rect ); }; /** * set max X and Y value, for size of container * @param {Packery.Rect} rect * @private */ Packery.prototype._setMaxXY = function( rect ) { this.maxX = Math.max( rect.x + rect.width, this.maxX ); this.maxY = Math.max( rect.y + rect.height, this.maxY ); }; /** * set the width and height of a rect, applying columnWidth and rowHeight * @param {Element} elem * @param {Packery.Rect} rect */ Packery.prototype._setRectSize = function( elem, rect ) { var size = getSize( elem ); var w = size.outerWidth; var h = size.outerHeight; // size for columnWidth and rowHeight, if available // only check if size is non-zero, #177 if ( w || h ) { w = this._applyGridGutter( w, this.columnWidth ); h = this._applyGridGutter( h, this.rowHeight ); } // rect must fit in packer rect.width = Math.min( w, this.packer.width ); rect.height = Math.min( h, this.packer.height ); }; /** * fits item to columnWidth/rowHeight and adds gutter * @param {Number} measurement - item width or height * @param {Number} gridSize - columnWidth or rowHeight * @returns measurement */ Packery.prototype._applyGridGutter = function( measurement, gridSize ) { // just add gutter if no gridSize if ( !gridSize ) { return measurement + this.gutter; } gridSize += this.gutter; // fit item to columnWidth/rowHeight var remainder = measurement % gridSize; var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; return measurement; }; Packery.prototype._getContainerSize = function() { if ( this.options.isHorizontal ) { return { width: this.maxX - this.gutter }; } else { return { height: this.maxY - this.gutter }; } }; // -------------------------- stamp -------------------------- // /** * makes space for element * @param {Element} elem */ Packery.prototype._manageStamp = function( elem ) { var item = this.getItem( elem ); var rect; if ( item && item.isPlacing ) { rect = item.placeRect; } else { var offset = this._getElementOffset( elem ); rect = new Rect({ x: this.options.isOriginLeft ? offset.left : offset.right, y: this.options.isOriginTop ? offset.top : offset.bottom }); } this._setRectSize( elem, rect ); // save its space in the packer this.packer.placed( rect ); this._setMaxXY( rect ); }; // -------------------------- methods -------------------------- // function verticalSorter( a, b ) { return a.position.y - b.position.y || a.position.x - b.position.x; } function horizontalSorter( a, b ) { return a.position.x - b.position.x || a.position.y - b.position.y; } Packery.prototype.sortItemsByPosition = function() { var sorter = this.options.isHorizontal ? horizontalSorter : verticalSorter; this.items.sort( sorter ); }; /** * Fit item element in its current position * Packery will position elements around it * useful for expanding elements * * @param {Element} elem * @param {Number} x - horizontal destination position, optional * @param {Number} y - vertical destination position, optional */ Packery.prototype.fit = function( elem, x, y ) { var item = this.getItem( elem ); if ( !item ) { return; } // prepare internal properties this._getMeasurements(); // stamp item to get it out of layout this.stamp( item.element ); // required for positionPlaceRect item.getSize(); // set placing flag item.isPlacing = true; // fall back to current position for fitting x = x === undefined ? item.rect.x: x; y = y === undefined ? item.rect.y: y; // position it best at its destination item.positionPlaceRect( x, y, true ); this._bindFitEvents( item ); item.moveTo( item.placeRect.x, item.placeRect.y ); // layout everything else this.layout(); // return back to regularly scheduled programming this.unstamp( item.element ); this.sortItemsByPosition(); // un set placing flag, back to normal item.isPlacing = false; // copy place rect position item.copyPlaceRectPosition(); }; /** * emit event when item is fit and other items are laid out * @param {Packery.Item} item * @private */ Packery.prototype._bindFitEvents = function( item ) { var _this = this; var ticks = 0; function tick() { ticks++; if ( ticks != 2 ) { return; } _this.dispatchEvent( 'fitComplete', null, [ item ] ); } // when item is laid out item.on( 'layout', function() { tick(); return true; }); // when all items are laid out this.on( 'layoutComplete', function() { tick(); return true; }); }; // -------------------------- resize -------------------------- // // debounced, layout on resize Packery.prototype.resize = function() { // don't trigger if size did not change var size = getSize( this.element ); // check that this.size and size are there // IE8 triggers resize on body size change, so they might not be var hasSizes = this.size && size; var innerSize = this.options.isHorizontal ? 'innerHeight' : 'innerWidth'; if ( hasSizes && size[ innerSize ] == this.size[ innerSize ] ) { return; } this.layout(); }; // -------------------------- drag -------------------------- // /** * handle an item drag start event * @param {Element} elem */ Packery.prototype.itemDragStart = function( elem ) { this.stamp( elem ); var item = this.getItem( elem ); if ( item ) { item.dragStart(); } }; /** * handle an item drag move event * @param {Element} elem * @param {Number} x - horizontal change in position * @param {Number} y - vertical change in position */ Packery.prototype.itemDragMove = function( elem, x, y ) { var item = this.getItem( elem ); if ( item ) { item.dragMove( x, y ); } // debounce var _this = this; // debounce triggering layout function delayed() { _this.layout(); delete _this.dragTimeout; } this.clearDragTimeout(); this.dragTimeout = setTimeout( delayed, 40 ); }; Packery.prototype.clearDragTimeout = function() { if ( this.dragTimeout ) { clearTimeout( this.dragTimeout ); } }; /** * handle an item drag end event * @param {Element} elem */ Packery.prototype.itemDragEnd = function( elem ) { var item = this.getItem( elem ); var itemDidDrag; if ( item ) { itemDidDrag = item.didDrag; item.dragStop(); } // if elem didn't move, or if it doesn't need positioning // unignore and unstamp and call it a day if ( !item || ( !itemDidDrag && !item.needsPositioning ) ) { this.unstamp( elem ); return; } // procced with dragged item classie.add( item.element, 'is-positioning-post-drag' ); // save this var, as it could get reset in dragStart var onLayoutComplete = this._getDragEndLayoutComplete( elem, item ); if ( item.needsPositioning ) { item.on( 'layout', onLayoutComplete ); item.moveTo( item.placeRect.x, item.placeRect.y ); } else if ( item ) { // item didn't need placement item.copyPlaceRectPosition(); } this.clearDragTimeout(); this.on( 'layoutComplete', onLayoutComplete ); this.layout(); }; /** * get drag end callback * @param {Element} elem * @param {Packery.Item} item * @returns {Function} onLayoutComplete */ Packery.prototype._getDragEndLayoutComplete = function( elem, item ) { var itemNeedsPositioning = item && item.needsPositioning; var completeCount = 0; var asyncCount = itemNeedsPositioning ? 2 : 1; var _this = this; return function onLayoutComplete() { completeCount++; // don't proceed if not complete if ( completeCount != asyncCount ) { return true; } // reset item if ( item ) { classie.remove( item.element, 'is-positioning-post-drag' ); item.isPlacing = false; item.copyPlaceRectPosition(); } _this.unstamp( elem ); // only sort when item moved _this.sortItemsByPosition(); // emit item drag event now that everything is done if ( itemNeedsPositioning ) { _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); } // listen once return true; }; }; /** * binds Draggabilly events * @param {Draggabilly} draggie */ Packery.prototype.bindDraggabillyEvents = function( draggie ) { draggie.on( 'dragStart', this.handleDraggabilly.dragStart ); draggie.on( 'dragMove', this.handleDraggabilly.dragMove ); draggie.on( 'dragEnd', this.handleDraggabilly.dragEnd ); }; /** * binds jQuery UI Draggable events * @param {jQuery} $elems */ Packery.prototype.bindUIDraggableEvents = function( $elems ) { $elems .on( 'dragstart', this.handleUIDraggable.start ) .on( 'drag', this.handleUIDraggable.drag ) .on( 'dragstop', this.handleUIDraggable.stop ); }; Packery.Rect = Rect; Packery.Packer = Packer; return Packery; }));