Можно ли оптимизировать слой встроенной тепловой карты в Google Maps API для анимации? - PullRequest
0 голосов
/ 17 июня 2019

Context : Встроенный слой тепловой карты в API Карт Google не имеет встроенной поддержки анимации, поэтому я создал собственные анимации, используя requestAnimationFrame с вызовами API Карт для установки данных следующего кадра. Каждый кадр использует ~ 2500 точек данных для рендеринга тепловой карты и максимально достигает 4000 точек данных.

Проблема : Моя анимация имеет рывки каждые 5-10 циклов. Мне не нужна анимация для рендеринга 60 кадров в секунду, но я хочу, чтобы частота кадров была постоянной, а каждый шаг был <= 100 мс. В Devtools кадры анимации дают мне эту ошибку в верхней части стека вызовов: «Предупреждение: повторяющийся обработчик занял # мс.» </p>

Моя предполагаемая причина проблемы : Консоль разработчика показывает утечки памяти, * второстепенные GC, основные GC и DOM GC, связанные с вызовами Maps API. В частности, DOM GC соотносится с анимацией. (* JS Heap, Nodes и Listeners увеличиваются линейно).

Почему я задаю вопрос : Я довольно плохо знаком с API Карт Google, requestAnimationFrame и управлением памятью в JavaScript, поэтому прежде всего я хочу убедиться, что правильно понимаю проблему. Во-вторых, я хочу посмотреть, есть ли способ оптимизировать слой тепловой карты для анимации или мой подход ошибочен.

Наиболее важные ресурсы, с которыми я консультировался :
Документация по API Карт Google
Руководство Google по производительности в сети
Вопрос StackOverflow, в котором задаются вопросы об очень простых и коротких анимациях тепловой карты API Карт

Код
Все в пределах d3.csv ('data').
Установить рекурсивный запросAnimationFrame:

const periodDuration = 100; // ms
const timeStart = performance.now();

const frameTick = timestamp => {
  if (timestamp - timeStart >= periodDuration) {
    timeStart = timestamp;
    transitionToNextPeriod(); // shown in next code snippet
  }  
  requestAnimationFrame(frameTick);
};

requestAnimationFrame(frameTick);

transitionToNextPeriod увеличивает время, затем фильтрует данные и завершает работу, устанавливая тепловую карту с обновленными данными:

function transitionToNextPeriod() {
  let batchedData = [],
      currPeriodData = [],
      addMin = 0;
      prevMin = min,
      prevDate = date,
      currMin = 0;

  // batch the next 'x' # of mins for one batchedData call after `while` loop
  while (++addMin <= 7){
    if (prevMin + addMin === 60){
      if (hour + 1 === 24){
        hour = 0;
        date++;
      } else {
        hour++
      } 
    }

    // Now with current minute, filter data and add to batchedData
    currMin = ((prevMin + addMin) % 60);

    let newTime = `${hour}:${zeroPad(currMin)}`;

    // Filter based on current time
    let currFilter = dayData.filter( d => d.StartTime.indexOf( ` ${newTime}` ) !== -1);

    prevPeriodData = prevPeriodData.filter( d => d.EndTime.indexOf( ` ${newTime}` ) === -1 );

    batchedData = [...batchedData, ...currFilter ];
  } // End while

  batchedData = [...batchedData, ...prevPeriodData];  
  prevPeriodData = batchedData;
  min = currMin;

  // Update the maps.LatLng data with new data, then set heatmap data
  batchedData.forEach( (d,i) => {
    // Check for last datum in current period
    if (i + 1 === batchedData.length){
      heatmap.setData(currPeriodData); // PROBLEM: about every 7th call to setData results in jank
    } else {
      currPeriodData.push(new google.maps.LatLng( d.Lat , d.Long ));
    }
  })
} // End transitionToNextPeriod()
...