Влияет ли requestAnimationFrame на переходы CSS?

Возможно ли, что requestAnimationFrame мешает работе других переходов CSS?

У меня есть функция requestAnimationFrame, которая перемещает позицию контейнера div. Обновление выполняется при каждом запросе кадра. Контейнер div содержит анимацию CSS:

.container {
  ...
  animation: pulse 2s infinite;
  ...
}

  @keyframes pulse {
    0%   { transform: scale(1); opacity: 1; }
    70%  { transform: scale(3); opacity: 0; }
    100% { transform: scale(1); opacity: 0; }
  }

Анимация CSS работает нормально, пока я НЕ вызываю requestAnimationFrame или прекращаю делать запросы.

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

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

this.animationId = requestAnimationFrame((timestamp) => {
  setTimeout(() => {
    this.animateContainer(timestamp)
  }, 50)
})

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

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

РЕДАКТИРОВАТЬ:

Почему я использую requestAnimationFrame и анимацию CSS?

requestAnimationFrame используется для интерполяции координат маркера на карте. Фактическое положение для X и Y рассчитывается картой в зависимости от холста. Затем анимация CSS используется для анимации этого маркера.


person Denis Loh    schedule 20.09.2019    source источник
comment
Было бы полезно, если бы вы могли создать работающий пример, который имитирует проблему, с которой вы столкнулись.   -  person Emiel Zuurbier    schedule 20.09.2019
comment
Я создал пример здесь: jsfiddle.net/jLeyc6aw/2 Вы можете видеть, что точка не оживляющий. Когда вы закомментируете rAF в строках 30 и 36 и прокомментируете строку 33, точка анимируется.   -  person Denis Loh    schedule 20.09.2019
comment
Это не имеет ничего общего с requestAnimationFrame, но с тем, как вы добавляете marker на карту. В функции animateMarker вы продолжаете добавлять маркер каждый раз, когда он вызывается. Это сбрасывает маркер и, следовательно, анимацию. Проверьте свою модифицированную скрипту, например jsfiddle   -  person Emiel Zuurbier    schedule 20.09.2019
comment
@EmielZuurbier, возможно, вы захотите опубликовать это как ответ, и вопрос, и ответы могут помочь будущим читателям. Однако Денис, было бы здорово, если бы вы могли отредактировать свой вопрос и хотя бы включить проблемную часть, например, свою функцию animateMarker   -  person Kaiido    schedule 20.09.2019


Ответы (1)


Причина проблемы в вашем коде связана не с requestAnimationFrame, а с функцией, которую вызывает rAF.

В animateMarker вы добавляете один и тот же маркер каждый раз, когда вызывается requestAnimationFrame. Это должно быть возможно. Однако, поскольку вы хотите показать анимацию ключевых кадров CSS на маркере, это не сработает. Это связано с тем, что каждый раз, когда вызывается marker.addTo(map), маркер быстро удаляется и снова добавляется, а также сбрасывает анимацию ключевых кадров.

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

var map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v11',
  center: [0, 0],
  zoom: 2
});

var el = document.createElement('div');
var dot = document.createElement('div');
dot.className = 'mapboxgl-user-location-dot';
el.appendChild(dot);

// Set radius globally.
var radius = 20;

// Add marker before animate loop.
var marker = new mapboxgl.Marker(el)
  .setLngLat(      
    Math.cos(0 / 1000) * 20,
    Math.sin(0 / 1000) * 20
  ]);
  .addTo(map);

// Change only the position in the animation loop without re-adding the marker.
function animateMarker(timestamp) {

  // Update the data to a new position based on the animation timestamp. The
  // divisor in the expression `timestamp / 1000` controls the animation speed.
  marker.setLngLat([
    Math.cos(timestamp / 1000) * radius,
    Math.sin(timestamp / 1000) * radius
  ]);  

  // Request the next frame of the animation.
  requestAnimationFrame(animateMarker);
}

// Start the animation.
requestAnimationFrame(animateMarker);
person Emiel Zuurbier    schedule 20.09.2019