Обновление позиций после изменений

Packery управляет расположением элементов на основе алгоритма упаковки прямоугольников. Каждый элемент сетки имеет координаты, которые рассчитываются библиотекой при инициализации и при любых изменениях структуры контейнера. Когда элементы добавляются, удаляются, изменяют размер или перетаскиваются, библиотека должна выполнить перерасчёт координат для сохранения плотной упаковки.

Обновление позиций представляет собой процесс повторного выполнения алгоритма раскладки. Во время этого процесса Packery анализирует текущие размеры элементов, вычисляет доступные области и размещает элементы так, чтобы минимизировать пустое пространство.

Перерасчёт может происходить:

  • автоматически (например, после drag-and-drop),
  • вручную через методы API,
  • в ответ на изменения DOM,
  • после загрузки изображений или изменения размеров элементов.

Правильное управление обновлением позиций критически важно для производительности интерфейса и корректной визуальной структуры.


Метод layout()

Основной способ принудительного обновления расположения элементов — метод layout().

Этот метод заставляет Packery пересчитать позиции всех элементов контейнера.

var pckry = new Packery('.grid', {
  itemSelector: '.grid-item',
  gutter: 10
});

// принудительный перерасчёт
pckry.layout();

При вызове метода происходит:

  1. очистка текущей карты размещения,
  2. повторный анализ размеров элементов,
  3. последовательное размещение элементов,
  4. обновление CSS-координат.

Метод используется в случаях:

  • динамического изменения размеров элементов,
  • изменения содержимого карточек,
  • после загрузки асинхронных данных,
  • при переключении режимов отображения.

Важно учитывать, что layout() пересчитывает всю сетку, поэтому частые вызовы могут приводить к заметной нагрузке на интерфейс.


Перерасчёт после изменения размеров элементов

Изменение размеров элементов напрямую влияет на алгоритм упаковки. Если элемент увеличился или уменьшился, его прежняя позиция может стать недействительной.

Типичная ситуация — изменение высоты карточки после загрузки данных.

item.classList.add('expanded');
pckry.layout();

Без повторного layout могут появиться проблемы:

  • наложение элементов,
  • появление пустых областей,
  • нарушение структуры сетки.

Packery не отслеживает изменение размеров элементов автоматически, поэтому разработчик должен инициировать перерасчёт.


Использование shiftLayout()

Метод shiftLayout() выполняет более мягкий перерасчёт позиций. В отличие от layout(), он старается сохранить текущее расположение элементов и лишь корректирует их смещение.

pckry.shiftLayout();

Основные особенности:

  • минимизирует перемещение элементов,
  • полезен при небольших изменениях,
  • снижает визуальные скачки интерфейса.

Этот метод часто используется после drag-операций или небольших изменений размеров элементов.


Обновление после загрузки изображений

Одна из самых распространённых проблем — изменение размеров элементов после загрузки изображений. До загрузки браузер может не знать реальную высоту контента.

В результате:

  • Packery вычисляет неправильную высоту элемента,
  • после загрузки изображение расширяет блок,
  • сетка разрушается.

Для решения используется библиотека imagesLoaded.

imagesLoaded('.grid', function() {
  pckry.layout();
});

Такой подход гарантирует, что перерасчёт произойдёт только после загрузки всех изображений.

В более динамичных интерфейсах применяется вариант:

imagesLoaded('.grid').on('progress', function() {
  pckry.layout();
});

В этом случае layout обновляется постепенно по мере загрузки изображений.


Перерасчёт после добавления элементов

При динамическом добавлении новых элементов используется метод appended().

var newItems = document.querySelectorAll('.new-item');

grid.append(...newItems);
pckry.appended(newItems);

Метод выполняет два действия:

  1. добавляет элементы в систему Packery,
  2. пересчитывает их позиции относительно существующих элементов.

После этого обычно вызывается:

pckry.layout();

Если элементы добавляются пакетами, лучше выполнять перерасчёт один раз после всех операций.


Обновление после удаления элементов

Удаление элементов требует освобождения занимаемого пространства.

pckry.remove(element);
pckry.layout();

Packery:

  • удаляет элемент из внутренней структуры,
  • пересчитывает карту свободного пространства,
  • перемещает оставшиеся элементы.

Без вызова layout() в сетке останутся пустые области.


Работа с reloadItems()

Если DOM-структура контейнера была изменена напрямую, Packery может потерять актуальное состояние элементов.

В этом случае используется метод reloadItems().

pckry.reloadItems();
pckry.layout();

Метод:

  1. повторно считывает элементы контейнера,
  2. обновляет внутренний список объектов,
  3. позволяет корректно выполнить последующий layout.

Типичные сценарии применения:

  • массовое изменение DOM,
  • фильтрация элементов,
  • перерисовка шаблонов.

Обновление позиций при drag-and-drop

Packery тесно интегрируется с системой перетаскивания. При перемещении элементов происходит автоматическое обновление позиций.

Внутренний механизм работает следующим образом:

  1. элемент захватывается пользователем,
  2. Packery резервирует пространство,
  3. при перемещении пересчитывается потенциальная позиция,
  4. остальные элементы сдвигаются.

После завершения операции выполняется окончательный layout.

Пример подключения:

pckry.bindDraggabillyEvents(draggie);

В большинстве случаев ручной вызов layout() после drag-операций не требуется.


Перерасчёт при изменении размеров окна

Ширина контейнера напрямую влияет на размещение элементов. При изменении размеров окна Packery может автоматически перестраивать сетку.

Эта функция контролируется параметром resize.

var pckry = new Packery('.grid', {
  resize: true
});

Если автоматический режим отключён, перерасчёт выполняется вручную.

window.addEventListener('resize', function() {
  pckry.layout();
});

При частых resize-событиях рекомендуется использовать debounce или throttle, чтобы избежать избыточных перерасчётов.


Оптимизация частоты обновлений

Частые вызовы layout() могут ухудшить производительность, особенно при большом количестве элементов.

Основные методы оптимизации:

Группировка операций

Вместо нескольких перерасчётов лучше выполнить один.

Плохо:

pckry.appended(item1);
pckry.layout();

pckry.appended(item2);
pckry.layout();

Лучше:

pckry.appended([item1, item2]);
pckry.layout();

Отложенный перерасчёт

Использование requestAnimationFrame помогает синхронизировать обновление с циклом отрисовки браузера.

requestAnimationFrame(function() {
  pckry.layout();
});

Debounce для resize

let timeout;

window.addEventListener('resize', function() {
  clearTimeout(timeout);

  timeout = setTimeout(function() {
    pckry.layout();
  }, 200);
});

Такой подход предотвращает десятки перерасчётов при изменении размеров окна.


Обновление после фильтрации элементов

Фильтрация часто выполняется через скрытие элементов.

element.style.display = 'none';
pckry.layout();

После скрытия Packery пересчитывает расположение оставшихся элементов.

Если элементы снова отображаются:

element.style.display = '';
pckry.layout();

Альтернативный вариант — временное удаление элементов из системы Packery и их повторное добавление.


Отладка проблем с позиционированием

Некорректное обновление позиций может проявляться в нескольких формах:

  • элементы перекрываются,
  • остаются пустые области,
  • элементы располагаются вне контейнера.

Наиболее распространённые причины:

1. Отсутствие вызова layout()

После изменения размеров элементов сетка не пересчитывается.

2. Асинхронная загрузка контента

Изображения и данные изменяют размеры карточек после первоначальной раскладки.

3. Прямое изменение DOM

Если элементы добавляются без использования API Packery, библиотека не знает о новых объектах.

Рекомендуемая последовательность действий:

pckry.reloadItems();
pckry.layout();

Внутренний алгоритм перерасчёта

При обновлении layout Packery использует внутреннюю систему rect packing.

Основные этапы:

  1. контейнер разбивается на виртуальные области,
  2. создаётся список свободных прямоугольников,
  3. элементы размещаются последовательно,
  4. свободное пространство перерасчитывается.

Этот алгоритм обеспечивает:

  • плотное размещение элементов,
  • отсутствие наложений,
  • минимизацию пустых зон.

При каждом вызове layout() структура свободных областей строится заново, что позволяет корректно учитывать любые изменения размеров элементов.