UNPKG

@material-git/all

Version:
125 lines (123 loc) 5.67 kB
import { MdGridTileTooWideError } from './grid-list-errors'; /** * Class for determining, from a list of tiles, the (row, col) position of each of those tiles * in the grid. This is necessary (rather than just rendering the tiles in normal document flow) * because the tiles can have a rowspan. * * The positioning algorithm greedily places each tile as soon as it encounters a gap in the grid * large enough to accommodate it so that the tiles still render in the same order in which they * are given. * * The basis of the algorithm is the use of an array to track the already placed tiles. Each * element of the array corresponds to a column, and the value indicates how many cells in that * column are already occupied; zero indicates an empty cell. Moving "down" to the next row * decrements each value in the tracking array (indicating that the column is one cell closer to * being free). */ export var TileCoordinator = (function () { function TileCoordinator(numColumns, tiles) { var _this = this; /** Index at which the search for the next gap will start. */ this.columnIndex = 0; /** The current row index. */ this.rowIndex = 0; this.tracker = new Array(numColumns); this.tracker.fill(0, 0, this.tracker.length); this.positions = tiles.map(function (tile) { return _this._trackTile(tile); }); } Object.defineProperty(TileCoordinator.prototype, "rowCount", { /** Gets the total number of rows occupied by tiles */ get: function () { return this.rowIndex + 1; }, enumerable: true, configurable: true }); Object.defineProperty(TileCoordinator.prototype, "rowspan", { /** Gets the total span of rows occupied by tiles. * Ex: A list with 1 row that contains a tile with rowspan 2 will have a total rowspan of 2. */ get: function () { var lastRowMax = Math.max.apply(Math, this.tracker); // if any of the tiles has a rowspan that pushes it beyond the total row count, // add the difference to the rowcount return lastRowMax > 1 ? this.rowCount + lastRowMax - 1 : this.rowCount; }, enumerable: true, configurable: true }); /** Calculates the row and col position of a tile. */ TileCoordinator.prototype._trackTile = function (tile) { // Find a gap large enough for this tile. var gapStartIndex = this._findMatchingGap(tile.colspan); // Place tile in the resulting gap. this._markTilePosition(gapStartIndex, tile); // The next time we look for a gap, the search will start at columnIndex, which should be // immediately after the tile that has just been placed. this.columnIndex = gapStartIndex + tile.colspan; return new TilePosition(this.rowIndex, gapStartIndex); }; /** Finds the next available space large enough to fit the tile. */ TileCoordinator.prototype._findMatchingGap = function (tileCols) { if (tileCols > this.tracker.length) { throw new MdGridTileTooWideError(tileCols, this.tracker.length); } // Start index is inclusive, end index is exclusive. var gapStartIndex = -1; var gapEndIndex = -1; // Look for a gap large enough to fit the given tile. Empty spaces are marked with a zero. do { // If we've reached the end of the row, go to the next row. if (this.columnIndex + tileCols > this.tracker.length) { this._nextRow(); continue; } gapStartIndex = this.tracker.indexOf(0, this.columnIndex); // If there are no more empty spaces in this row at all, move on to the next row. if (gapStartIndex == -1) { this._nextRow(); continue; } gapEndIndex = this._findGapEndIndex(gapStartIndex); // If a gap large enough isn't found, we want to start looking immediately after the current // gap on the next iteration. this.columnIndex = gapStartIndex + 1; } while (gapEndIndex - gapStartIndex < tileCols); return gapStartIndex; }; /** Move "down" to the next row. */ TileCoordinator.prototype._nextRow = function () { this.columnIndex = 0; this.rowIndex++; // Decrement all spaces by one to reflect moving down one row. for (var i = 0; i < this.tracker.length; i++) { this.tracker[i] = Math.max(0, this.tracker[i] - 1); } }; /** * Finds the end index (exclusive) of a gap given the index from which to start looking. * The gap ends when a non-zero value is found. */ TileCoordinator.prototype._findGapEndIndex = function (gapStartIndex) { for (var i = gapStartIndex + 1; i < this.tracker.length; i++) { if (this.tracker[i] != 0) { return i; } } // The gap ends with the end of the row. return this.tracker.length; }; /** Update the tile tracker to account for the given tile in the given space. */ TileCoordinator.prototype._markTilePosition = function (start, tile) { for (var i = 0; i < tile.colspan; i++) { this.tracker[start + i] = tile.rowspan; } }; return TileCoordinator; }()); /** Simple data structure for tile position (row, col). */ export var TilePosition = (function () { function TilePosition(row, col) { this.row = row; this.col = col; } return TilePosition; }()); //# sourceMappingURL=tile-coordinator.js.map