Created
January 28, 2016 16:14
-
-
Save tzi/e01345d7f2022a2d2a8d to your computer and use it in GitHub Desktop.
Responsive photo grid with rowspan
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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