@s2ui/justified-gallery
Version:
A justifed gallery by s2ui.
69 lines (59 loc) • 2.04 kB
text/typescript
import { JustifiedGalleryOptions, JustifiedImageBox, Photo } from "./types";
import { calculateLastRowOffset, loadImageAspectRatio, splitIntoRows } from "./utils/helpers";
async function computeLayout(
options: JustifiedGalleryOptions
): Promise<JustifiedImageBox[]> {
const {
container,
rowHeight: targetRowHeight,
gap,
lastRow = "left",
} = options;
const images = Array.from(
container.querySelectorAll("img")
) as HTMLImageElement[];
if (!images.length) return [];
// Load images with aspect ratios
const photos: Photo[] = await Promise.all(images.map(loadImageAspectRatio));
const containerWidth = container.clientWidth;
const rows = splitIntoRows(photos, containerWidth, targetRowHeight, gap);
const layout: JustifiedImageBox[] = [];
let currentTop = 0;
rows.forEach(([start, end, rowWidth], rowIndex) => {
const row = photos.slice(start, end + 1);
const isLastRow = rowIndex === rows.length - 1;
const canJustify = !(isLastRow && lastRow !== "justify");
// Calculate row height
const adjustedRowHeight = canJustify
? ((containerWidth - (row.length - 1) * gap) / rowWidth) * targetRowHeight
: Math.min(
targetRowHeight,
((containerWidth - (row.length - 1) * gap) / rowWidth) *
targetRowHeight
);
let leftOffset =
isLastRow && lastRow !== "justify"
? calculateLastRowOffset(
lastRow,
containerWidth,
row,
adjustedRowHeight,
gap
)
: 0;
row.forEach((photo) => {
const width = Math.round(adjustedRowHeight * photo.ratio);
layout.push({
left: leftOffset,
top: currentTop,
width,
height: Math.round(adjustedRowHeight),
img: photo.img,
});
leftOffset += width + gap;
});
currentTop += Math.round(adjustedRowHeight) + gap;
});
return layout;
}
export { computeLayout };