Ограничение действий пользователя

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

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

Модификаторы применяются к операциям:

  • drag — перетаскивание
  • resize — изменение размеров
  • gesture — жесты (масштабирование, вращение)

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

Основные типы ограничений:

  • ограничение перемещения
  • ограничение изменения размеров
  • ограничение краёв элемента
  • привязка к сетке
  • ограничение размеров
  • ограничение координат указателя
  • комбинирование модификаторов

Архитектура модификаторов

Все ограничения в Interact.js реализуются через свойство modifiers, которое передаётся в конфигурацию взаимодействия.

Пример базовой структуры:

interact('.item')
  .draggable({
    modifiers: [
      interact.modifiers.restrict({
        restriction: 'parent'
      })
    ]
  })

Массив modifiers может содержать несколько модификаторов, которые применяются последовательно.

Каждый модификатор:

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

Последовательность обработки:

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

Ограничение перемещения (restrict)

Модификатор restrict ограничивает положение указателя или элемента внутри определённой области.

Ограничение внутри родительского контейнера

interact('.box')
  .draggable({
    modifiers: [
      interact.modifiers.restrict({
        restriction: 'parent',
        endOnly: true
      })
    ]
  })

Параметры:

параметр описание
restriction область ограничения
endOnly ограничение применяется только в конце действия
elementRect какая часть элемента участвует в проверке

Значение restriction может быть:

  • 'parent'
  • 'self'
  • CSS-селектор
  • DOM-элемент
  • объект координат

Ограничение произвольной областью

interact('.box')
  .draggable({
    modifiers: [
      interact.modifiers.restrict({
        restriction: {
          left: 100,
          top: 100,
          right: 500,
          bottom: 400
        }
      })
    ]
  })

Объект ограничения содержит координаты:

  • left
  • top
  • right
  • bottom

Элемент не сможет выйти за указанные границы.


Ограничение по координатам указателя

Иногда требуется ограничивать не сам элемент, а положение курсора.

interact('.item')
  .draggable({
    modifiers: [
      interact.modifiers.restrict({
        restriction: 'parent',
        elementRect: { left: 0, right: 0, top: 1, bottom: 1 }
      })
    ]
  })

Параметр elementRect определяет, какая часть элемента участвует в вычислении ограничения.

Значения:

  • 0 — край элемента
  • 1 — противоположный край

Ограничение перемещения элемента (restrictRect)

Модификатор restrictRect работает аналогично restrict, но ограничивает границы элемента, а не положение указателя.

interact('.card')
  .draggable({
    modifiers: [
      interact.modifiers.restrictRect({
        restriction: 'parent'
      })
    ]
  })

Отличие:

restrict restrictRect
ограничивает указатель ограничивает элемент
может позволить элементу выходить частично не позволяет выходить за границы

Этот модификатор чаще используется для UI-конструкторов и редакторов.


Ограничение изменения размеров (restrictSize)

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

Модификатор restrictSize ограничивает размеры.

interact('.panel')
  .resizable({
    edges: { left: true, right: true, bottom: true, top: true },

    modifiers: [
      interact.modifiers.restrictSize({
        min: { width: 100, height: 50 },
        max: { width: 600, height: 400 }
      })
    ]
  })

Параметры:

параметр описание
min минимальные размеры
max максимальные размеры

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


Ограничение краёв (restrictEdges)

Иногда необходимо ограничить позиции краёв элемента при изменении размеров.

Модификатор restrictEdges применяется при resizable.

interact('.window')
  .resizable({
    edges: { left: true, right: true, bottom: true, top: true },

    modifiers: [
      interact.modifiers.restrictEdges({
        outer: 'parent'
      })
    ]
  })

Параметры:

параметр значение
outer внешняя граница
inner внутренняя граница

Пример ограничения:

interact.modifiers.restrictEdges({
  outer: {
    left: 0,
    top: 0,
    right: 800,
    bottom: 600
  }
})

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


Привязка к сетке (snap)

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

Модификатор snap фиксирует координаты к ближайшей точке сетки.

interact('.item')
  .draggable({
    modifiers: [
      interact.modifiers.snap({
        targets: [
          interact.snappers.grid({ x: 50, y: 50 })
        ],
        range: Infinity
      })
    ]
  })

Параметры:

параметр описание
targets массив точек привязки
range радиус активации
relativePoints точки элемента

Настройка сетки

interact.snappers.grid({
  x: 20,
  y: 20
})

Элемент будет перемещаться только кратно:

  • 20px по горизонтали
  • 20px по вертикали

Привязка нескольких точек

Можно задавать несколько целей.

interact.modifiers.snap({
  targets: [
    { x: 100, y: 100 },
    { x: 300, y: 300 }
  ],
  range: 50
})

Если элемент попадает в радиус 50px, координаты автоматически корректируются.


Привязка краёв (snapEdges)

Для операций изменения размеров используется snapEdges.

interact('.panel')
  .resizable({
    modifiers: [
      interact.modifiers.snapEdges({
        targets: [
          interact.snappers.grid({ x: 50, y: 50 })
        ]
      })
    ]
  })

Края элемента будут “прилипать” к сетке.

Это особенно полезно в:

  • графических редакторах
  • системах layout-дизайна
  • редакторах макетов

Привязка размеров (snapSize)

Модификатор snapSize ограничивает размеры к сетке.

interact('.box')
  .resizable({
    modifiers: [
      interact.modifiers.snapSize({
        targets: [
          interact.snappers.grid({ width: 100, height: 100 })
        ]
      })
    ]
  })

Размеры элемента будут изменяться шагами:

  • ширина кратна 100px
  • высота кратна 100px

Комбинирование ограничений

Модификаторы могут применяться одновременно.

Пример:

  • ограничение контейнером
  • привязка к сетке
  • минимальный размер
interact('.widget')
  .draggable({
    modifiers: [
      interact.modifiers.restrictRect({
        restriction: 'parent'
      }),

      interact.modifiers.snap({
        targets: [
          interact.snappers.grid({ x: 20, y: 20 })
        ]
      })
    ]
  })
  .resizable({
    modifiers: [
      interact.modifiers.restrictSize({
        min: { width: 100, height: 100 }
      })
    ]
  })

Последовательность выполнения модификаторов:

  1. вычисление координат
  2. restrictRect
  3. snap
  4. передача события

Ограничение динамической функцией

Вместо фиксированной области можно использовать функцию.

interact('.item')
  .draggable({
    modifiers: [
      interact.modifiers.restrict({
        restriction: function () {
          return document.querySelector('.container')
        }
      })
    ]
  })

Функция возвращает область ограничения.

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

  • менять границы во время работы
  • учитывать масштаб
  • учитывать прокрутку

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

Иногда требуется ограничивать не центр элемента, а конкретную точку.

Используется relativePoints.

interact.modifiers.snap({
  targets: [interact.snappers.grid({ x: 50, y: 50 })],

  relativePoints: [
    { x: 0, y: 0 },
    { x: 0.5, y: 0.5 },
    { x: 1, y: 1 }
  ]
})

Точки означают:

значение позиция
0,0 левый верх
0.5,0.5 центр
1,1 правый низ

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


Ограничение только после завершения действия

Параметр endOnly откладывает ограничение до окончания взаимодействия.

interact.modifiers.restrict({
  restriction: 'parent',
  endOnly: true
})

Поведение:

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

Такой подход используется для:

  • плавных интерфейсов
  • drag-preview
  • редакторов интерфейсов

Ограничение жестов

Ограничения применяются и к жестам масштабирования.

interact('.canvas')
  .gesturable({
    modifiers: [
      interact.modifiers.restrictSize({
        min: { width: 200, height: 200 },
        max: { width: 1000, height: 1000 }
      })
    ]
  })

Это предотвращает:

  • чрезмерное масштабирование
  • слишком маленькие элементы

Практический пример: ограниченный draggable-элемент

interact('.block')
  .draggable({
    modifiers: [
      interact.modifiers.restrictRect({
        restriction: 'parent'
      }),

      interact.modifiers.snap({
        targets: [
          interact.snappers.grid({ x: 25, y: 25 })
        ]
      })
    ],

    listeners: {
      move(event) {
        const target = event.target

        const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx
        const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy

        target.style.transform = `translate(${x}px, ${y}px)`

        target.setAttribute('data-x', x)
        target.setAttribute('data-y', y)
      }
    }
  })

Результат:

  • элемент перемещается
  • остаётся внутри контейнера
  • координаты привязаны к сетке 25px

Практический пример: ограниченный resizable-элемент

interact('.resizable')
  .resizable({
    edges: { left: true, right: true, bottom: true, top: true },

    modifiers: [
      interact.modifiers.restrictEdges({
        outer: 'parent'
      }),

      interact.modifiers.restrictSize({
        min: { width: 150, height: 100 }
      }),

      interact.modifiers.snapSize({
        targets: [
          interact.snappers.grid({ width: 50, height: 50 })
        ]
      })
    ],

    listeners: {
      move(event) {
        let { x, y } = event.target.dataset

        x = (parseFloat(x) || 0) + event.deltaRect.left
        y = (parseFloat(y) || 0) + event.deltaRect.top

        Object.assign(event.target.style, {
          width: `${event.rect.width}px`,
          height: `${event.rect.height}px`,
          transform: `translate(${x}px, ${y}px)`
        })

        Object.assign(event.target.dataset, { x, y })
      }
    }
  })

Поведение:

  • изменение размеров ограничено контейнером
  • минимальные размеры 150×100
  • размеры привязаны к сетке 50px

Производительность ограничений

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

Рекомендации:

  • избегать сложных вычислений в функциях ограничения
  • минимизировать количество модификаторов
  • использовать endOnly, если возможно
  • не выполнять DOM-поиск внутри обработчиков

Оптимально:

1–3 модификатора на взаимодействие

Это обеспечивает плавность даже при высокой частоте событий.


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

Ограничение действий пользователя используется в различных типах интерфейсов.

Конструкторы интерфейсов

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

Графические редакторы

  • привязка объектов
  • ограничение масштабирования
  • контроль границ холста

Панели и окна

  • запрет выхода за экран
  • минимальные размеры
  • прилипающие края

Drag-and-drop системы

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

Ключевые модификаторы Interact.js

модификатор назначение
restrict ограничение указателя
restrictRect ограничение элемента
restrictEdges ограничение краёв
restrictSize ограничение размеров
snap привязка координат
snapEdges привязка краёв
snapSize привязка размеров

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