Приоритеты действий

Interact.js предоставляет гибкую систему для обработки взаимодействий с элементами DOM, таких как перетаскивание, масштабирование и жесты. Одним из ключевых аспектов является управление приоритетами действий (action priorities), что позволяет определить, какое действие будет выполняться, когда несколько действий потенциально конфликтуют друг с другом.

В Interact.js каждое взаимодействие имеет тип действия (drag, resize, gesture). Когда пользователь начинает взаимодействие, библиотека определяет, какое действие должно иметь приоритет, исходя из конфигурации и состояния взаимодействия.


Настройка действий и их приоритетов

Каждое действие в Interact.js настраивается через объект конфигурации interactable. Основные параметры:

interact(target)
  .draggable({ /* настройки drag */ })
  .resizable({ /* настройки resize */ })
  .gesturable({ /* настройки gesture */ });

Для приоритета действий важны следующие свойства:

  • actionChecker — функция, которая позволяет переопределить стандартный выбор действия. Она вызывается при каждом событии pointerDown и должна возвращать тип действия (drag, resize или gesture) или null.
  • ignoreFrom и allowFrom — фильтры элементов, на которых действия не должны срабатывать или с которых они должны срабатывать.
  • max и maxPerAction — ограничения на количество одновременно активных действий.

Пример использования actionChecker

interact('.item')
  .draggable({
    actionChecker: function (event, defaultAction, interactable, element) {
      if (event.shiftKey) {
        return 'resize'; // при нажатом Shift выполняем resize
      }
      return defaultAction; // иначе стандартное действие
    }
  })
  .resizable({
    edges: { left: true, right: true, bottom: true, top: true }
  });

В этом примере приоритет resize будет иметь преимущество, если пользователь удерживает клавишу Shift. В остальных случаях выполняется стандартное действие (drag).


Понимание max и maxPerAction

Interact.js поддерживает множественные одновременные взаимодействия через пальцы или указатели. Параметры max и maxPerAction позволяют управлять ограничениями:

  • max — максимальное количество одновременных взаимодействий на элементе.
  • maxPerAction — максимальное количество одновременных действий конкретного типа.
interact('.multi-touch')
  .draggable({ maxPerAction: 1 })
  .resizable({ maxPerAction: 2 });

Здесь элемент может одновременно выполнять до двух ресайзов (например, двумя пальцами), но только один drag.


Приоритет при конфликтующих действиях

Если на элементе назначены несколько действий, Interact.js использует следующие правила:

  1. Если actionChecker возвращает конкретное действие, оно выполняется.
  2. Если несколько действий возможны одновременно, библиотека применяет приоритет в порядке gesture > resize > drag.
  3. Ограничения max и maxPerAction могут заблокировать некоторые действия.

Пример конфликтной ситуации

Элемент настроен для drag и resize одновременно. Пользователь нажимает на угол элемента и перемещает мышь:

  • Без actionChecker — Interact.js выбирает действие resize, так как движение начинается с края (edges).
  • Если пользователь начинает движение с центра элемента — выполняется drag.

Использование actionChecker позволяет явно контролировать приоритет:

interact('.conflict')
  .draggable({
    actionChecker: (event, defaultAction) => {
      if (event.pointerType === 'touch') {
        return 'gesture'; // тач предпочитает жесты
      }
      return defaultAction;
    }
  })
  .resizable({ edges: { top: true, left: true } })
  .gesturable({});

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

Приоритет действий можно изменять в процессе работы приложения, реагируя на состояние:

let isResizeMode = false;

interact('.dynamic')
  .draggable({
    actionChecker: (event, defaultAction) => {
      return isResizeMode ? 'resize' : defaultAction;
    }
  })
  .resizable({ edges: { top: true, right: true } });

// переключение режима
document.getElementById('toggle').addEventListener('click', () => {
  isResizeMode = !isResizeMode;
});

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


Особенности работы с множественными указателями

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

  • Разделение действий по указателям — каждый пальцевый указатель может выполнять разные действия, но ограничения maxPerAction влияют на количество одновременных операций.
  • События onstart, onmove, onend передают объект pointer, чтобы можно было точно отслеживать активные действия.

Пример:

interact('.multi-pointer')
  .draggable({ maxPerAction: 2 })
  .on('dragstart', event => {
    console.log('Drag начался на указателе', event.pointer.id);
  })
  .on('dragmove', event => {
    console.log('Двигаем указатель', event.pointer.id);
  });

Выводы по управлению приоритетами

  • actionChecker — основной инструмент для явного задания приоритета действий.
  • max и maxPerAction позволяют управлять одновременными взаимодействиями.
  • Стандартный порядок приоритетов: gesture > resize > drag.
  • Для сложных интерфейсов приоритеты можно изменять динамически, в зависимости от контекста.

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