masonry.js 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. import { clamp } from "./utils.js";
  2. export function setupMasonries() {
  3. const masonryContainers = document.getElementsByClassName("masonry");
  4. for (let i = 0; i < masonryContainers.length; i++) {
  5. const container = masonryContainers[i];
  6. const options = {
  7. minColumnWidth: container.dataset.minColumnWidth || 330,
  8. maxColumns: container.dataset.maxColumns || 6,
  9. };
  10. const items = Array.from(container.children);
  11. let previousColumnsCount = 0;
  12. const render = function() {
  13. const columnsCount = clamp(
  14. Math.floor(container.offsetWidth / options.minColumnWidth),
  15. 1,
  16. Math.min(options.maxColumns, items.length)
  17. );
  18. if (columnsCount === previousColumnsCount) {
  19. return;
  20. } else {
  21. container.textContent = "";
  22. previousColumnsCount = columnsCount;
  23. }
  24. const columnsFragment = document.createDocumentFragment();
  25. for (let i = 0; i < columnsCount; i++) {
  26. const column = document.createElement("div");
  27. column.className = "masonry-column";
  28. columnsFragment.append(column);
  29. }
  30. // poor man's masonry
  31. // TODO: add an option that allows placing items in the
  32. // shortest column instead of iterating the columns in order
  33. for (let i = 0; i < items.length; i++) {
  34. columnsFragment.children[i % columnsCount].appendChild(items[i]);
  35. }
  36. container.append(columnsFragment);
  37. };
  38. const observer = new ResizeObserver(() => requestAnimationFrame(render));
  39. observer.observe(container);
  40. }
  41. }