Почему моя анимация замедляется, когда я использую Листовку и наложение пикселей?

#javascript #webgl #pixi.js

Вопрос:

Я использую плагин WebGL pixi-overlay для листовки https://github.com/manubb/Leaflet.ИнкрУстация пикси. Существуют маркеры, которые имеют анимационный эффект при перемещении карты листовки, и они отображаются с помощью средства визуализации WebGL. Я оптимизировал анимацию WebGL, но все равно иногда выпадали кадры. Я полагаю, это потому, что рендеринг анимации листовок пересекается с рендерингом WebGL. Я обнаружил, что в Листовке используются CSS-переходы. Я хотел бы знать, как повысить производительность, чтобы избежать пропущенных кадров.

Вкладка «Производительность»

animation.js:

   container,
  flags,
  timestamp,
  delta,
  targetScale,
  currentScale
) {
  var time = flags.scalingTime;
  var progress = timestamp - time;
  var lambda = progress / delta;
  if (lambda > 1) lambda = 1;
  lambda = lambda * (0.4   lambda * (2.2   lambda * -1.6));
  for (var markerSprite of container.children) {
    markerSprite.scale.set(
      currentScale   lambda * (targetScale - currentScale)
    );
  }
  if (progress >= delta) {
    flags.scaling = false;
  }
}

function transformFading(container, flags, timestamp, delta, coef = 1) {
  var fadeMarkers, time;
  if (coef > 0) {
    fadeMarkers = flags.fadeInMarkers;
    time = flags.fadingInTime;
  } else {
    fadeMarkers = flags.fadeOutMarkers;
    time = flags.fadingOutTime;
  }
  var progress = timestamp - time;
  var lambda = progress / delta;
  if (lambda > 1) lambda = 1;
  lambda = lambda * (0.4   lambda * (2.2   lambda * -1.6));

  for (var markerSprite of fadeMarkers) {
    markerSprite.alpha = coef > 0 ? lambda : 1 - lambda;
  }
  if (progress >= delta) {
    if (coef < 0) {
      flags.fadingOut = false;
      container.removeChild(...fadeMarkers);
    } else flags.fadingIn = false;
  }
}

export function animate(
  flags,
  timestamp,
  container,
  renderer,
  delta,
  targetScale = null,
  currentScale = null
) {
  if (flags.scaling)
    transformScaling(
      container,
      flags,
      timestamp,
      delta,
      targetScale,
      currentScale
    );
  if (flags.fadingIn) transformFading(container, flags, timestamp, delta, 1);
  if (flags.fadingOut) transformFading(container, flags, timestamp, delta, -1);
  renderer.render(container);
  if (flags.scaling || flags.fadingIn || flags.fadingOut) {
    var frame = requestAnimationFrame(() =>
      animate(
        flags,
        Date.now(),
        container,
        renderer,
        delta,
        targetScale,
        currentScale
      )
    );
  } else {
    cancelAnimationFrame(frame);
    flags.animateRunning = false;
  }
}
 

основной цикл: (для простоты был удален некоторый код)

 export function preloadApp(map) {
  var loader = new PIXI.Loader();
  loadTextures(loader);
  loader.load(function (loader, resources) {
    var container = new PIXI.Container();
    var prevZoom
    var renderer, project;
    var pointToCoords = {};
    var sentCount = 0;
    var firstDraw = true;
    var flags = {
      scaling: false,
      fadingIn: false,
      fadingOut: false,
      animateRunning: false,
    };
    var delta = 200;
    var pixiOverlay = L.pixiOverlay(function (utils) { // calls each time when map position updates
      if (typeof renderer === "undefined") {
        renderer = utils.getRenderer();
      }
      var zoom = map.getZoom();
      //...

      sentCount  = 1; // count moving

      sendRequest("GET", `http://localhost:5000/api/markers/${requestString}`)
        .then((mapObjects) => {
          setTimeout(() => { // Imitation timeout
            // if position was changed multiiple times we should work with the last one
            if (sentCount > 1) {
              sentCount -= 1;
              return;
            }

            var scale = utils.getScale();
            project = utils.latLngToLayerPoint; // projection
            pointToCoords.cur = utils.layerPointToLatLng;

            var fadeOutMarkers = [
              ...container.children.filter(
                //[rule]
              ),
            ];

            flags.fadingOut = true;
            flags.fadingOutTime = Date.now();
            flags.fadeOutMarkers = fadeOutMarkers;

            if (!flags.animateRunning) {
              animate(
                flags,
                timestamp,
                container,
                renderer,
                delta,
                targetScale,
                currentScale
              );
              flags.animateRunning = true;
            }

            // оставляем в контейнере только те элементы, которые совпадают с теми, что пришли с сервера

            var clusterPoints = mapObjects;
            var fadeInMarkers = [];
            for (let /*!*/ coordinate in clusterPoints) {
              let objectCoords = clusterPoints[coordinate].coords; // координаты в виде массива
              var options = {
                objectCoords,
                project,
                scale,
                map,
                container,
                renderer,
                clusterPoints,
                mapObjects,
                pointToCoords,
              };
              var newMarker = createMarker(options);
              newMarker.alpha = 0;
              fadeInMarkers.push(newMarker);
              container.addChild(newMarker);
            }
            prevZoom = zoom;
            flags.fadingIn = true;
            flags.fadeInMarkers = fadeInMarkers;
            flags.fadingInTime = Date.now();
            if (!flags.animateRunning) {
              animate(
                flags,
                timestamp,
                container,
                renderer,
                delta,
                targetScale,
                currentScale
              );
              flags.animateRunning = true;
            }
            sentCount -= 1;
          }, 0);
        })
        .catch((err) => {
          alert(err);
        });

      // Rescaling
      if (zoom !== prevZoom amp;amp; !firstDraw) {
        var scale = utils.getScale();
        var targetScale = 1 / scale / 4;
        var currentScale = container.children[0].transform.scale.x;

        var timestamp = Date.now();
        flags.scaling = true;
        flags.scalingTime = timestamp;

        if (!flags.animateRunning) {
          animate(
            flags, 
            timestamp,
            container,
            renderer,
            delta,
            targetScale,
            currentScale
          );
          flags.animateRunning = true;
        }
      }
      prevZoom = zoom;

      firstDraw = false;
      // if(!flags.animateRunning) ???
      renderer.render(container);
    }, pixiContainer);
    pixiOverlay.addTo(map);
  });
}
 

Комментарии:

1. листовка определенно не является картографической библиотекой на основе WebGL. Вы не можете попросить его отрисовывать с помощью webgl. Для этого типа библиотеки посмотрите на mapbox или arcgis js api. Я бы пересмотрел ваш вопрос, чтобы сосредоточиться на том, какая у вас проблема конкретно с тем, как происходит анимация с наложением пикселей.

2. @Сет Луцке, Спасибо. Я обновил свой вопрос