MapBox GL JS标记/图标动画效果较慢 [英] MapBox GL JS marker/icon animation slow performance

查看:258
本文介绍了MapBox GL JS标记/图标动画效果较慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用mapbox-gl-js为地图上的一个坐标到另一个坐标设置许多图像的动画. 当我尝试添加最多15张图像及以上图像时,它会变成慢速帧速率. 在chrome上执行性能配置文件会给我方法Actor.receive的提示,该方法花费了最多的计算时间.

I'm using mapbox-gl-js to animate many image from one coordinates to another on the map. It become slow frame rate when I try to add up to 15 image and above. Doing performance profile on chrome give me the hint to method Actor.receive, which cost the most computational time.

/**
 * Util.js
 */
 var linesDataSource = {
  "type": "FeatureCollection",
  "features": [{
    "type": "Feature",
    "properties": {},
    "geometry": {
      "type": "LineString",
      "coordinates": [
        [
          151.15684390068054, -33.89568424317427
        ],
        [
          151.15808844566345, -33.89606717952166
        ],
        [
          151.15779876708984, -33.89680633086413
        ],
        [
          151.15740180015564, -33.897794824453406
        ],
        [
          151.1582601070404, -33.8980085512904
        ],
        [
          151.1609423160553, -33.89863191817193
        ],
        [
          151.16222977638245, -33.89621857248702
        ],
        [
          151.16639256477356, -33.89771467675142
        ],
        [
          151.1694610118866, -33.898916884371395
        ],
        [
          151.17089867591858, -33.896298721595166
        ],
        [
          151.17217540740964, -33.899014841282515
        ],
        [
          151.1714780330658, -33.899192944468965
        ],
        [
          151.17132782936093, -33.89878330658397
        ],
        [
          151.1719822883606, -33.8985784869035
        ],
        [
          151.17339849472046, -33.89839147720036
        ],
        [
          151.17376327514648, -33.89825789858986
        ],
        [
          151.17332339286804, -33.897269410368615
        ],
        [
          151.1732053756714, -33.89697553328233
        ],
        [
          151.17341995239258, -33.89662822269281
        ],
        [
          151.17295861244202, -33.896263099778615
        ],
        [
          151.17225050926208, -33.89589797530112
        ],
        [
          151.17136001586914, -33.89561299901295
        ],
        [
          151.17184281349182, -33.894758064434605
        ],
        [
          151.17200374603271, -33.89455323508587
        ],
        [
          151.17257237434387, -33.89148073582115
        ],
        [
          151.17042660713196, -33.89132042847356
        ],
        [
          151.17168188095093, -33.88838140703873
        ],
        [
          151.1716067790985, -33.887606557247125
        ],
        [
          151.16321682929993, -33.888274531623864
        ],
        [
          151.16029858589172, -33.88777577791726
        ],
        [
          151.1591076850891, -33.88790937294604
        ],
        [
          151.15857124328613, -33.8892809364742
        ],
        [
          151.1584746837616, -33.89006467716016
        ],
        [
          151.15894675254822, -33.89009139546571
        ],
        [
          151.15893602371216, -33.889806399775104
        ]
      ]
    }
  }]
}


var PI = Math.PI;
var TWO_PI = Math.PI * 2;

function rotation(start, end) {
  var dx = end[0] - start[0];
  var dy = end[1] - start[1];
  return -Math.atan2(dy, dx) * (180 / PI);
};

function lerp(v0, v1, t) {
  return v0 * (1 - t) + v1 * t
}

function interpolateAngle(fromAngle, toAngle, t) {
  fromAngle = fromAngle * (PI / 180);
  toAngle = toAngle * (PI / 180);

  fromAngle = (fromAngle + TWO_PI) % TWO_PI;
  toAngle = (toAngle + TWO_PI) % TWO_PI;

  var diff = Math.abs(fromAngle - toAngle);
  if (diff < PI) {
    return lerp(fromAngle, toAngle, t) * (180 / PI);
  } else {
    if (fromAngle > toAngle) {
      fromAngle = fromAngle - TWO_PI;
      return lerp(fromAngle, toAngle, t) * (180 / PI);
    } else if (toAngle > fromAngle) {
      toAngle = toAngle - TWO_PI;
      return lerp(fromAngle, toAngle, t) * (180 / PI);
    }
  }
}





/**
 * Car.js
 */
function Car(name, map, path) {
  this.name = name;
  this.map = map;
  this.path = path;
  this.speed = 90; // 30 km/h
  this.accumulatedDistance = 0;
  this.previousPos = this.path.features[0].geometry.coordinates[0];
  this.previousAngle = 0;

  this.animate = function(frameInfo) {

    this.accumulatedDistance += ((frameInfo.deltaTime / 3600) * this.speed);
    var point = turf.along(this.path.features[0], this.accumulatedDistance, 'kilometers');

    this.map.getSource(this.name).setData(point);

    var newAngle = rotation(this.previousPos, point.geometry.coordinates);
    var rotate = interpolateAngle(this.previousAngle, newAngle, 0.1);

    this.map.setLayoutProperty(this.name, 'icon-rotate', rotate);

    this.previousAngle = rotate;
    this.previousPos = point.geometry.coordinates;
  };

  this.init = function() {
    this.map.addSource(this.name, {
      "type": "geojson",
      "data": {
        "type": "FeatureCollection",
        "features": [{
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": this.previousPos
          }
        }]
      }
    });

    this.map.addLayer({
      "id": this.name,
      "type": "symbol",
      "source": this.name,
      "layout": {
        "icon-image": "car",
        "icon-size": 1,
        "icon-rotate": 0,
        "icon-rotation-alignment": "map"
      }
    });
  };
}





/**
 * MapBoxTest.js
 */
var destination = {};
var cars = [];
var style = 'mapbox://styles/mapbox/streets-v9'; //'/TestEmptyProject/mapbox-gl-styles-master/styles/basic-v8.json';
//'http://localhost:8080/styles/osm-bright.json';  // 'http://localhost:8080/styles/fiord-color-gl.json'


mapboxgl.accessToken = 'pk.eyJ1IjoiZW1wZXJvcjE0MTIiLCJhIjoiY2ozYTYxdXFlMDM3dzJyczRsa2M5ZjE3aCJ9.9zQGtkSsjOw6npohN6ba3w';
var map = new mapboxgl.Map({
  container: 'map',
  style: style,
  center: [132.133333, -23.116667],
  zoom: 3
});

// Used to increment the value of the point measurement against the linesData.
var counter = 0;
var linesData = {};

function addCar() {
  var car = new Car("Car_" + counter, map, linesData);
  car.init();
  cars.push(car);
  ++counter;
}

var previousTimeStamp = 0;
// Add a source and layer displaying a point which will be animated in a circle.
function animate(timeStamp) {
  if (timeStamp <= previousTimeStamp) {
    console.log("Wrong timeStamp, now: " + timeStamp + "\t previous: " + previousTimeStamp);
    return;
  }

  var i;
  var frameInfo = {
    "timeStamp": timeStamp,
    "previousTimeStamp": previousTimeStamp,
    "deltaTime": (timeStamp - previousTimeStamp) / 1000
  };
  previousTimeStamp = timeStamp;

  for (i = 0; i < cars.length; ++i) {
    var car = cars[i];
    car.animate(frameInfo);
  }
  requestAnimationFrame(animate);
}

map.on('load', function() {

  console.log("map load");

  map.loadImage('https://maxcdn.icons8.com/office/PNG/40/Transport/railroad_car-40.png', function(error, image) {
    if (error) throw error;
    map.addImage('car', image);
  });

  //fetch('./lines.geojson', {
  //method: 'get'
//}).then(function(response) {
 // return response.json();
//}).then(function(data) {

  linesData = linesDataSource;
  var coordinates = linesData.features[0].geometry.coordinates;

  var bounds = coordinates.reduce(function(bounds, coord) {
    return bounds.extend(coord);
  }, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));

  map.fitBounds(bounds, {
    padding: 20,
    duration: 2000
  });

  map.addSource('lines', {
    "type": "geojson",
    "data": linesData
  });

  map.addLayer({
    "id": "route",
    "source": "lines",
    "type": "line",
    "paint": {
      "line-width": 2,
      "line-color": "#007cbf"
    }
  });
  // }).catch(function(err) {
  //console.log("error: " + err);
//}); 

document.getElementById('addCar').addEventListener('click', function() {
addCar();
});


});


requestAnimationFrame(animate);

 body {
   margin: 0;
   padding: 0;
 }
 
 #map {
   position: absolute;
   top: 0;
   bottom: 0;
   width: 100%;
 }
 
 .overlay {
   position: absolute;
   top: 10px;
   left: 10px;
 }
 
 .overlay button {
   font: 600 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
   background-color: #3386c0;
   color: #fff;
   display: inline-block;
   margin: 0;
   padding: 10px 20px;
   border: none;
   cursor: pointer;
   border-radius: 3px;
 }
 
 .overlay button:hover {
   background-color: #4ea0da;
 }

<script src="https://master.fieldtec.com/vendor/custom-component-modules/car_tracking_animation/scripts/turf.min.js"></script>
<link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.css" rel="stylesheet"/>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.js"></script>

<body>
  <div id='map'></div>
  <div class='overlay'>
    <button id='addCar'>Add Car</button>
  </div>
</body>

推荐答案

使用一个来源处理所有动画.使用setData()更新每一帧的源.使用数据驱动的样式从源渲染一层.这将使用您的GPU渲染动画. 通过减少层数和setData()调用,这将大大提高性能.

Do all of your animation with one source. Update the source each frame with setData(). Render one layer from the source using data-driven styles. This will use your GPU to render animations. This will improve performance considerably by reducing the number of layers and setData() calls.

使用一层和一个来源在GL JS中进行动画处理的示例代码: https://bl.ocks .org/ryanbaumann/9b9b52e09ff86d1ce8346fb76b681427

Example code of animating in GL JS with one layer and one source: https://bl.ocks.org/ryanbaumann/9b9b52e09ff86d1ce8346fb76b681427

这篇关于MapBox GL JS标记/图标动画效果较慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆