Блокировка осей перемещения

Interact.js предоставляет гибкие средства управления поведением интерактивных элементов, включая возможность ограничивать перемещение по определённым осям. Блокировка осей перемещения особенно полезна при создании интерфейсов с ограниченной свободой перемещения, например, вертикальных или горизонтальных слайдеров, таблиц с перетаскиванием колонок, draggable-панелей и игровых интерфейсов.

Ограничение движения с помощью axis

Основной способ блокировки осей в Interact.js — использование опции axis в настройках draggable. Она принимает строковые значения:

  • "x" — разрешено перемещение только по горизонтали; вертикальная координата фиксирована.
  • "y" — разрешено перемещение только по вертикали; горизонтальная координата фиксирована.
  • null или отсутствие свойства — движение свободное по обеим осям.

Пример кода:

interact('.draggable-horizontal')
  .draggable({
    axis: 'x', // движение только по горизонтали
    inertia: true,
    modifiers: [
      interact.modifiers.restrictRect({
        restriction: 'parent',
        endOnly: true
      })
    ],
    listeners: {
      move(event) {
        const target = event.target;
        const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
        target.style.transform = `translate(${x}px, 0px)`;
        target.setAttribute('data-x', x);
      }
    }
  });

interact('.draggable-vertical')
  .draggable({
    axis: 'y', // движение только по вертикали
    inertia: true,
    listeners: {
      move(event) {
        const target = event.target;
        const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
        target.style.transform = `translate(0px, ${y}px)`;
        target.setAttribute('data-y', y);
      }
    }
  });

В этом примере элемент с классом .draggable-horizontal может перемещаться только по оси X, а .draggable-vertical — только по оси Y. Использование атрибутов data-x и data-y позволяет сохранять текущее положение элемента для корректного обновления при каждом событии move.

Комбинация с ограничениями области

Ограничение движения по оси часто комбинируется с модификаторами restrictRect или restrictEdges, чтобы элемент не выходил за пределы контейнера:

interact('.draggable')
  .draggable({
    axis: 'x',
    modifiers: [
      interact.modifiers.restrictRect({
        restriction: '.container',
        endOnly: true
      })
    ],
    listeners: {
      move(event) {
        const target = event.target;
        const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
        target.style.transform = `translate(${x}px, 0px)`;
        target.setAttribute('data-x', x);
      }
    }
  });

Здесь элемент может двигаться только по горизонтали и не покинет границы .container. Модификатор endOnly: true гарантирует, что ограничение будет применяться только после завершения перетаскивания, позволяя плавную анимацию в процессе.

Блокировка с помощью событий

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

interact('.draggable-dynamic')
  .draggable({
    listeners: {
      move(event) {
        const target = event.target;
        let x = parseFloat(target.getAttribute('data-x')) || 0;
        let y = parseFloat(target.getAttribute('data-y')) || 0;

        // Разрешить движение только по вертикали, если Shift не нажат
        if (!event.shiftKey) {
          y += event.dy;
        } else {
          x += event.dx;
        }

        target.style.transform = `translate(${x}px, ${y}px)`;
        target.setAttribute('data-x', x);
        target.setAttribute('data-y', y);
      }
    }
  });

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

Использование с инерцией и snap

Блокировка осей корректно работает вместе с инерцией (inertia) и системой привязки к сетке (snap). Пример горизонтального элемента с привязкой к шагу 50px:

interact('.draggable-snap')
  .draggable({
    axis: 'x',
    inertia: true,
    modifiers: [
      interact.modifiers.snap({
        targets: [interact.snappers.grid({ x: 50, y: 50 })],
        range: Infinity,
        relativePoints: [{ x: 0, y: 0 }]
      })
    ],
    listeners: {
      move(event) {
        const target = event.target;
        const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
        target.style.transform = `translate(${x}px, 0px)`;
        target.setAttribute('data-x', x);
      }
    }
  });

Snap гарантирует, что даже при свободном перетаскивании элемент будет «прилипать» к шагам сетки, сохраняя движение по одной оси.

Рекомендации по оптимизации

  • Для сложных интерфейсов лучше использовать axis в сочетании с модификаторами, чтобы разгрузить обработчики dragmove от лишней логики блокировки.
  • Хранение координат в data-x и data-y обеспечивает стабильное поведение при динамическом изменении трансформаций.
  • При анимации или интеграции с CSS-переходами стоит учитывать endOnly: true для плавного завершения движения.
  • Для элементов с ограниченной осью движение по другой оси должно быть явно зафиксировано в transform или style, иначе браузер может интерпретировать небольшие смещения как дрожание элемента.

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