我使用mapbox-gl-js在地图上为一个坐标到另一个坐标设置动画。 当我尝试添加最多15个图像时,它会变慢帧速率。 在chrome上执行性能配置文件会给出方法Actor.receive的提示,这会花费最多的计算时间。
/**
* 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);
&#13;
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;
}
&#13;
<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>
&#13;
答案 0 :(得分:3)
使用一个源完成所有动画。使用setData()更新每个帧的源。使用数据驱动样式从源渲染一个图层。这将使用您的GPU来渲染动画。 这将通过减少层数和setData()调用来显着提高性能。
使用一层和一个源在GL JS中制作动画的示例代码:https://bl.ocks.org/ryanbaumann/9b9b52e09ff86d1ce8346fb76b681427
答案 1 :(得分:2)
要为数百个图标制作动画,在着色器中而不是在javascript中制作动画效率更高。这允许您利用GPU的强大功能。这是一个演示:http://misterfresh.github.io/mapbox-animation/