Управление перерисовкой

Gridstack.js управляет размещением и визуальным обновлением элементов сетки через систему внутренних вычислений координат и последующей синхронизации с DOM. Перерисовка происходит каждый раз, когда изменяется положение, размер или состояние одного или нескольких виджетов.

Основная цель механизма — минимизировать количество операций с DOM и обеспечить плавность интерфейса при сложных перестановках элементов.

Внутренний алгоритм перерисовки опирается на несколько ключевых этапов:

  1. обновление модели сетки
  2. перерасчёт координат
  3. применение изменений к DOM
  4. уведомление подписчиков событий

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


Модель сетки и источник истины

Gridstack.js использует внутреннюю структуру данных, представляющую сетку и размещённые в ней элементы. Эта модель содержит информацию:

  • координаты элемента (x, y)
  • размеры (width, height)
  • ограничения
  • состояние блокировки
  • принадлежность к сетке

Внутренний объект узла обычно имеет структуру:

{
  x: 0,
  y: 0,
  w: 2,
  h: 2,
  id: "widget-1",
  locked: false,
  noResize: false,
  noMove: false
}

Любое изменение сначала происходит в этой модели, и только затем отражается в DOM. Благодаря этому перерисовка может быть отложена или объединена.


Триггеры перерисовки

Перерисовка сетки запускается при следующих действиях:

Изменение позиции элемента

  • перемещение drag-and-drop
  • программное изменение координат

Изменение размера

  • resize через пользовательский интерфейс
  • изменение размеров через API

Добавление или удаление виджетов

  • addWidget()
  • removeWidget()

Изменение структуры сетки

  • изменение количества колонок
  • изменение размеров контейнера

Восстановление состояния

  • загрузка сохранённой конфигурации

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


Внутренний цикл обновления

При изменении положения одного элемента Gridstack выполняет последовательность действий:

  1. фиксирует изменения в модели
  2. проверяет коллизии
  3. перераспределяет конфликтующие элементы
  4. обновляет координаты
  5. применяет изменения к DOM

Псевдологика процесса:

update node
check collisions
resolve layout
update engine state
apply to DOM
emit events

Важная особенность — DOM не обновляется после каждого промежуточного шага.


Батч-перерисовка (batch updates)

Для повышения производительности Gridstack поддерживает режим групповых изменений.

Методы:

grid.batchUpdate(true)
grid.batchUpdate(false)

Когда batch режим включён:

  • изменения накапливаются
  • DOM не обновляется
  • пересчёт сетки откладывается

После выключения режима выполняется единая перерисовка.

Пример:

grid.batchUpdate();

grid.addWidget({x:0, y:0, w:2, h:2});
grid.addWidget({x:2, y:0, w:2, h:2});
grid.addWidget({x:4, y:0, w:2, h:2});

grid.batchUpdate(false);

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


Метод engine._notify()

После завершения вычислений Gridstack уведомляет систему событий.

Это используется для:

  • обновления интерфейса
  • синхронизации состояния
  • уведомления слушателей

Типичные события:

  • change
  • added
  • removed
  • dragstop
  • resizestop

Пример подписки:

grid.on('change', function(event, items) {
  console.log(items);
});

Событие change содержит список элементов, которые были изменены.


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

Gridstack поддерживает адаптацию сетки к изменению размеров родительского элемента.

Используется механизм наблюдения за размерами (ResizeObserver). Когда ширина контейнера меняется:

  1. пересчитывается ширина колонок
  2. обновляются координаты элементов
  3. выполняется перерисовка

Пример реакции на изменение колонок:

grid.column(6);

После вызова происходит перераспределение элементов.


Обновление координат через CSS

Gridstack применяет позиционирование элементов через CSS-свойства.

Основные свойства:

left
top
width
height

В некоторых конфигурациях используется CSS-трансформация:

transform: translate(...)

Такой подход позволяет:

  • снизить количество layout-пересчётов
  • повысить плавность анимации

Пример DOM-элемента:

<div class="grid-stack-item"
     gs-x="1"
     gs-y="2"
     gs-w="3"
     gs-h="2">
</div>

Атрибуты gs-* используются как декларативное описание положения.


Оптимизация перерисовки

Gridstack реализует несколько оптимизаций.

Минимизация изменений DOM

Обновляются только элементы, координаты которых изменились.

Отложенная перерисовка

Batch-режим позволяет объединять операции.

Детекция коллизий

Алгоритм перемещает только необходимые элементы.

Кэширование размеров

Размеры колонок и строки вычисляются один раз.


Принудительная перерисовка

Иногда требуется обновить интерфейс вручную. Для этого используется метод:

grid._updateContainerHeight();

Или более безопасный вариант:

grid.commit();

Этот метод завершает batch-операции и применяет изменения.


Метод update()

Метод update() позволяет изменить свойства элемента и инициировать перерасчёт.

Пример:

grid.update(el, {
  x: 3,
  y: 1,
  w: 4,
  h: 2
});

Происходит:

  1. обновление модели
  2. проверка коллизий
  3. перерасчёт сетки
  4. перерисовка

Анимация при перерисовке

Gridstack поддерживает плавные анимации перемещения.

Активируется через CSS:

.grid-stack-item {
  transition: all 0.2s ease;
}

Когда координаты меняются, браузер анимирует изменение.

Анимация применяется к:

  • перемещению
  • изменению размеров
  • перестановке элементов

Перерисовка при drag-операциях

Во время drag-операций сетка постоянно обновляет позицию временного элемента.

Алгоритм:

  1. пользователь перемещает элемент
  2. вычисляется ближайшая позиция сетки
  3. проверяются коллизии
  4. временно переставляются элементы
  5. интерфейс обновляется

После отпускания мыши выполняется окончательная фиксация.


Временные плейсхолдеры

Во время перетаскивания Gridstack использует placeholder-элемент.

Он:

  • показывает будущую позицию
  • не влияет на окончательную модель

Пример DOM:

<div class="grid-stack-placeholder"></div>

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


Перерисовка при загрузке состояния

Состояние сетки может восстанавливаться из JSON.

Пример:

grid.load(layout);

Алгоритм:

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

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

Изменение количества колонок вызывает глобальный пересчёт.

Метод:

grid.column(12);

Gridstack:

  • масштабирует координаты
  • пересчитывает ширину элементов
  • обновляет DOM

При уменьшении колонок возможны перестановки элементов.


Синхронизация состояния и DOM

После каждой перерисовки Gridstack поддерживает согласованность между:

  • внутренней моделью
  • DOM-атрибутами
  • CSS-позиционированием

DOM-атрибуты gs-x, gs-y, gs-w, gs-h всегда обновляются.

Это позволяет:

  • сериализовать состояние
  • использовать CSS-селекторы
  • интегрировать сторонние инструменты.

Управление перерисовкой через API

Основные методы:

batchUpdate

grid.batchUpdate(true);

commit

grid.commit();

update

grid.update(el, options);

load

grid.load(layout);

column

grid.column(n);

Комбинация этих методов позволяет полностью контролировать процесс перерисовки сетки.


Практические рекомендации по производительности

Группировать изменения

Всегда использовать batch-режим при массовых операциях.

Избегать лишних update

Каждый вызов update() может инициировать перерасчёт.

Ограничивать количество элементов

Большие сетки (100+ элементов) требуют аккуратного управления обновлениями.

Минимизировать CSS-эффекты

Сложные тени и фильтры могут замедлять анимацию.


Отладка перерисовки

При анализе поведения сетки полезно отслеживать события:

grid.on('change added removed', function(e, items) {
  console.log(items);
});

Также можно временно отключить анимации:

.grid-stack-item {
  transition: none;
}

Это помогает увидеть реальные изменения координат без задержек.


Взаимодействие с виртуальными DOM-фреймворками

При использовании с React, Vue или Angular важно учитывать:

  • Gridstack напрямую изменяет DOM
  • виртуальный DOM может перезаписывать изменения

Поэтому рекомендуется:

  • инициализировать Gridstack после рендера
  • синхронизировать состояние через события
  • избегать ручного изменения DOM элементов сетки.

Архитектурная роль GridStackEngine

Основная логика перерасчёта сетки находится в классе GridStackEngine.

Он отвечает за:

  • хранение модели
  • проверку коллизий
  • алгоритмы размещения
  • управление координатами

GridStackEngine не взаимодействует напрямую с DOM.

Это разделение позволяет:

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