Skip to content

Instantly share code, notes, and snippets.

@tzi
Created January 28, 2016 16:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tzi/e01345d7f2022a2d2a8d to your computer and use it in GitHub Desktop.
Save tzi/e01345d7f2022a2d2a8d to your computer and use it in GitHub Desktop.
Responsive photo grid with rowspan
var cellWidth = 220;
window.addEventListener("resize", reLayout);
reLayout();
function reLayout() {
var wrapperList = document.querySelectorAll('.wrapper');
for (var i = 0; i < wrapperList.length; i++) {
var innerWidth = getInnerWidth(wrapperList[i]);
var columnCount = Math.floor(innerWidth / cellWidth);
addPushClass(wrapperList[i], columnCount);
}
}
function getInnerWidth(wrapper) {
var width = wrapper.clientWidth;
var styles = getComputedStyle(wrapper);
var paddingLeft = parseFloat(styles.paddingLeft);
var paddingRight = parseFloat(styles.paddingRight);
var innerWidth = width - paddingLeft - paddingRight;
return innerWidth;
}
function addPushClass(wrapper, columnCount) {
var reservedCoords = [];
var currentCoords = [0, 0];
var cell;
var lastY = 0;
var lastYNeeded = 0;
for (var i = 0; i < wrapper.children.length; i++) {
cell = wrapper.children[i];
var isBig = isBigCell(cell);
var nextIterator = 1;
var offset = 0;
var push = 0;
var pullX = 0;
var pullY = 0;
if (isBig) {
// We only need a hack if there is more than 2 columns
cell.classList.toggle('re-layout', columnCount > 2);
// If there is not enough place left, we are on the next line
if (columnCount - currentCoords[0] < 2) {
currentCoords = [0, currentCoords[1] + 1];
}
// Next cell will be in to 2 more coordonates
nextIterator = 2;
}
// Calcul the offset needed to go where we should be
offset = getOffsetForNextAvailableCoords(nextIterator, currentCoords, reservedCoords, columnCount);
// If we need to force a end of line, we will ask the previous cell to pull
var remaingColumnOnLine = columnCount - currentCoords[0];
pullX = (remaingColumnOnLine < columnCount && remaingColumnOnLine <= offset) ? remaingColumnOnLine : 0;
if (i > 0) {
wrapper.children[i - 1].style.marginRight = (pullX * cellWidth) + 'px';
}
// If we need to move to the next line
if (offset - pullX >= columnCount) {
pullY = 1;
addEOL(cell);
}
// If we need to move on the same line, we push
if (pullY) {
push = 0;
} else {
push = offset - pullX;
}
cell.style.marginLeft = (push * cellWidth) + 'px';
// Update current coordonnates according to the offset
currentCoords = offsetCurrentCoords(currentCoords, columnCount, offset);
lastY = currentCoords[1];
// Save the coords reserved by the big element on the next line
if (isBig) {
reservedCoords.push([
currentCoords[0],
currentCoords[1] + 1
], [
currentCoords[0] + 1,
currentCoords[1] + 1
]);
lastYNeeded = currentCoords[1] + 1;
}
// Go to the next coordonates
currentCoords = offsetCurrentCoords(currentCoords, columnCount, nextIterator);
// We cleanup passed reserved coords
for (var j = 0; j < reservedCoords.length; j++) {
if (
reservedCoords[j][0] < currentCoords[0] &&
reservedCoords[j][1] < currentCoords[1]
) {
reservedCoords.splice(0, 1);
j--
}
}
}
// We check if the last big cell was on the last line.
if (lastY < lastYNeeded) {
addEOL(cell);
}
}
function getOffsetForNextAvailableCoords(cellSize, currentCoords, reservedCoords, columnCount) {
// Clone object
var iteratorCoords = [currentCoords[0], currentCoords[1]];
var offset = 0;
// There is no reservec coordonnates when there 2 or less columns
if (!reservedCoords.length || columnCount <= 2) {
return offset;
}
while (!isCoordsAvailable(cellSize, iteratorCoords, reservedCoords)) {
offset++;
offsetCurrentCoords(iteratorCoords, columnCount, 1);
}
return offset;
}
function isCoordsAvailable(cellSize, currentCoords, reservedCoords) {
for (var i = 0; i < cellSize; i++) {
for (var j = 0; j < reservedCoords.length; j++) {
if (
reservedCoords[j][0] == currentCoords[0] + i &&
reservedCoords[j][1] == currentCoords[1]
) {
return false;
}
}
}
return true;
}
function isBigCell(cell) {
return cell.classList.contains('favorite');
}
function addEOL(node) {
getPreviousBigCell(node).classList.remove('re-layout');
}
function getPreviousBigCell(node) {
while ((node = node.previousSibling)) {
if (!isNodeIgnorable(node) &&
isBigCell(node)
) {
return node;
}
}
return null;
}
function isNodeIgnorable(node) {
return (node.nodeType == 8) || // A comment node
(node.nodeType == 3); // a text node, all ws
}
function offsetCurrentCoords(currentCoords, columnCount, offset) {
currentCoords[0] += offset;
currentCoords[1] += Math.floor(currentCoords[0] / columnCount);
currentCoords[0] = currentCoords[0] % columnCount;
return currentCoords;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment