Множественные свойства

Множественные свойства в Popmotion представляют собой модель анимации, в которой изменяется не одно числовое значение, а целый набор параметров объекта одновременно. Такая форма используется для управления положением, размером, цветом, прозрачностью и любыми другими стилевыми или пользовательскими параметрами в рамках одной анимации.

В основе лежит объектная интерполяция: вместо передачи единственного значения для анимации задаются структуры вида from и to, содержащие несколько ключей. Каждый ключ интерполируется независимо, но синхронно по общему таймингу анимации.

Базовая форма анимации множественных свойств строится вокруг объекта:

import { animate } from 'popmotion';

animate({
  from: {
    x: 0,
    y: 0,
    opacity: 0
  },
  to: {
    x: 300,
    y: 150,
    opacity: 1
  },
  duration: 800
});

В данной конфигурации каждое свойство обрабатывается как независимая шкала интерполяции:

  • x изменяется от 0 до 300
  • y изменяется от 0 до 150
  • opacity изменяется от 0 до 1

Popmotion синхронизирует прогресс анимации между всеми ключами, используя единый временной контекст. Это позволяет гарантировать, что все изменения происходят согласованно по фазам easing-функции.

Принцип согласованного прогресса

Каждое свойство внутри объекта получает одинаковое значение прогресса t, вычисляемое из временной функции анимации. Затем применяется линейная или нелинейная интерполяция:

value = start + (end - start) * easing(t)

Для множественных свойств этот процесс повторяется для каждого ключа независимо, но с общим t.

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

Использование с styler и пакетная установка свойств

В большинстве практических сценариев множественные свойства применяются через styler, который агрегирует обновления DOM-элементов.

import { animate, styler } from 'popmotion';

const element = document.querySelector('.box');
const boxStyler = styler(element);

animate({
  from: {
    x: 0,
    y: 0,
    scale: 0.5
  },
  to: {
    x: 400,
    y: 200,
    scale: 1
  },
  duration: 600,
  onUpdate: (latest) => {
    boxStyler.set(latest);
  }
});

Метод set принимает объект и обновляет сразу несколько CSS-трансформаций или свойств. Это снижает количество операций с DOM и предотвращает промежуточные перерисовки.

Независимое управление свойствами через onUpdate

При необходимости более тонкого контроля применяется явная деструктуризация значений:

animate({
  from: { x: 0, y: 0 },
  to: { x: 300, y: 300 },
  onUpdate: ({ x, y }) => {
    element.style.transform = `translate(${x}px, ${y}px)`;
  }
});

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

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

Разнородные типы значений

Множественные свойства не ограничены числами. Поддерживаются строки, цвета и сложные структуры, если для них предусмотрена интерполяция.

Цветовые значения

animate({
  from: {
    background: 'rgb(0, 0, 0)',
    color: '#ffffff'
  },
  to: {
    background: 'rgb(255, 100, 50)',
    color: '#000000'
  },
  duration: 1000,
  onUpdate: (v) => {
    element.style.background = v.background;
    element.style.color = v.color;
  }
});

Интерполяция цветов выполняется поканально (R, G, B), что обеспечивает плавный переход без скачков.

Смешанные трансформации

Частый сценарий — комбинирование геометрических и визуальных параметров:

animate({
  from: {
    x: 0,
    y: 0,
    rotate: 0,
    scale: 0.8,
    opacity: 0
  },
  to: {
    x: 500,
    y: 200,
    rotate: 180,
    scale: 1,
    opacity: 1
  },
  duration: 900,
  onUpdate: (v) => {
    element.style.transform =
      `translate(${v.x}px, ${v.y}px) rotate(${v.rotate}deg) scale(${v.scale})`;

    element.style.opacity = v.opacity;
  }
});

Здесь наблюдается разделение ответственности:

  • трансформации агрегируются в transform
  • непрозрачность управляется отдельно
  • все свойства синхронизированы по времени

Частичное обновление свойств

При работе с объектами допускается неполное определение значений. Отсутствующие ключи не участвуют в интерполяции.

animate({
  from: { x: 0, y: 0 },
  to: { x: 300, y: 0 },
  onUpdate: (v) => {
    boxStyler.set({
      x: v.x
    });
  }
});

В таком случае только x подвергается изменению, а остальные свойства остаются неизменными. Это полезно для каскадных анимаций, где разные параметры управляются разными процессами.

Композиция множественных свойств и логика обновлений

При увеличении количества параметров возникает необходимость структурирования обновлений. Множественные свойства часто группируются по смысловым блокам:

  • позиционирование: x, y
  • трансформации: scale, rotate
  • визуальные эффекты: opacity, filter
  • пользовательские параметры: progress, state
animate({
  from: {
    x: 0,
    y: 0,
    scale: 0.5,
    blur: 10,
    progress: 0
  },
  to: {
    x: 200,
    y: 100,
    scale: 1,
    blur: 0,
    progress: 1
  },
  onUpdate: (v) => {
    element.style.transform =
      `translate(${v.x}px, ${v.y}px) scale(${v.scale})`;

    element.style.filter = `blur(${v.blur}px)`;

    element.dataset.progress = v.progress;
  }
});

Такая структура позволяет рассматривать анимацию как набор параллельных временных функций, объединённых общим источником времени.

Производительность при работе с множественными свойствами

Обновление нескольких свойств в одном onUpdate снижает количество вызовов рендера. Вместо множества операций применяется единая точка синхронизации:

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

Особенно заметен эффект при использовании styler, который оптимизирует запись через внутренние batching-механизмы.

Вложенные структуры и расширенные объекты

При усложнении интерфейсов используется вложенная структура объектов:

animate({
  from: {
    position: { x: 0, y: 0 },
    visual: { opacity: 0 }
  },
  to: {
    position: { x: 300, y: 200 },
    visual: { opacity: 1 }
  },
  onUpdate: (v) => {
    element.style.transform =
      `translate(${v.position.x}px, ${v.position.y}px)`;

    element.style.opacity = v.visual.opacity;
  }
});

Такая организация данных улучшает читаемость модели состояния и упрощает масштабирование анимационных сценариев при увеличении числа параметров.