AspectRatio - сохранение пропорций

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


Принцип работы aspectRatio

Опция aspectRatio задаёт отношение ширины к высоте элемента. Это отношение может быть:

  • Булевым значениемtrue сохраняет исходное соотношение сторон элемента при изменении размеров.
  • Числом – фиксированное отношение сторон, например, 16/9 или 1 для квадрата.

Пример базового использования:

interact('.resizable')
  .resizable({
    edges: { left: true, right: true, bottom: true, top: true },
    modifiers: [
      interact.modifiers.aspectRatio({
        ratio: true
      })
    ],
    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 });
      }
    }
  });

В этом примере:

  • edges задаёт, с каких сторон возможна растяжка.
  • modifiers.aspectRatio({ ratio: true }) сохраняет исходное соотношение сторон элемента.
  • В обработчике move обновляются размеры и позиция элемента.

Использование фиксированного соотношения сторон

Если необходимо, чтобы элемент всегда масштабировался в определённом соотношении, можно передать число в ratio. Например, для прямоугольника 16:9:

interact('.resizable-16-9')
  .resizable({
    edges: { left: true, right: true, bottom: true, top: true },
    modifiers: [
      interact.modifiers.aspectRatio({
        ratio: 16 / 9
      })
    ],
    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 });
      }
    }
  });

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


Настройка ограничений с сохранением пропорций

AspectRatio можно комбинировать с другими модификаторами для ограничения размеров элемента:

modifiers: [
  interact.modifiers.restrictSize({
    min: { width: 100, height: 100 },
    max: { width: 400, height: 400 }
  }),
  interact.modifiers.aspectRatio({ ratio: true })
]
  • restrictSize ограничивает минимальные и максимальные размеры.
  • aspectRatio гарантирует, что пропорции сохраняются даже при этих ограничениях.

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


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

Пропорцию можно менять во время работы приложения. Для этого можно обновлять параметр ratio через объект модификаторов:

const aspectModifier = interact.modifiers.aspectRatio({ ratio: 1 });

interact('.dynamic-resizable')
  .resizable({
    edges: { left: true, right: true, bottom: true, top: true },
    modifiers: [aspectModifier],
    listeners: { move: event => updateSize(event) }
  });

// Позже в коде
aspectModifier.ratio = 4 / 3;

Такой подход полезен для приложений, где пользователь может переключать формат, например, между квадратом, 4:3 и 16:9.


Взаимодействие с трансформациями

При сохранении пропорций важно учитывать текущие трансформации элемента, например translate или rotate. Interact.js корректно обновляет размеры и позицию, если в обработчике move применять event.deltaRect и учитывать смещения через dataset.

Пример правильного применения с transform:

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

Это позволяет сохранить пропорции, позицию и угол вращения одновременно.


Советы по использованию

  • Для квадратных элементов используйте ratio: 1.
  • Для медиа-блоков (видео, изображения) чаще всего используют соотношение 16:9 или 4:3.
  • Всегда проверяйте порядок модификаторов: сначала ограничения (restrictSize), затем сохранение пропорций (aspectRatio).
  • При динамическом изменении пропорций учитывайте текущие размеры, чтобы не было резкого скачка при переключении формата.

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