文章目录
Examples 解析
此处记录较复杂的示例,简单的会在后面整理的相关API中提及。
Animate a point along a route
1 线段插点
// Calculate the distance in kilometers between route start/end point.
var lineDistance = turf.length(route.features[0]);
var arc = [];
// Number of steps to use in the arc and animation, more steps means
// a smoother arc and animation, but too many steps will result in a
// low frame rate
var steps = 500;
// Draw an arc between the `origin` & `destination` of the two points
for (var i = 0; i < lineDistance; i += lineDistance / steps) {
var segment = turf.along(route.features[0], i);
arc.push(segment.geometry.coordinates);
}
// Update the route with calculated arc coordinates
route.features[0].geometry.coordinates = arc;
turf.length
计算线段长度
turf.along
计算一定距离在线段上的位置
2 icon角度的计算
var start = route.features[0].geometry.coordinates[
counter >= steps ? counter - 1 : counter
];
var end = route.features[0].geometry.coordinates[
counter >= steps ? counter : counter + 1
];
if (!start || !end) return;
point.features[0].properties.bearing = turf.bearing(
turf.point(start),
turf.point(end)
);
turf.bearing
计算两点之间的方向角
3 动画刷新
var counter = 0;
function animate() {
point.features[0].geometry.coordinates =
route.features[0].geometry.coordinates[counter];
// Update the source with this new data
map.getSource('point').setData(point);
// Request the next frame of animation as long as the end has not been reached
if (counter < steps) {
requestAnimationFrame(animate);
}
counter = counter + 1;
}
// Start the animation
animate(counter);
window.requestAnimationFrame()
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
Animate map camera around a point (3D)
旋转相机方法
function rotateCamera(timestamp) {
// clamp the rotation between 0 -360 degrees
// Divide timestamp by 100 to slow rotation to ~10 degrees / sec
map.rotateTo((timestamp / 100) % 360, { duration: 0 });
// Request the next frame of the animation.
requestAnimationFrame(rotateCamera);
}
// Start the animation.
rotateCamera(0);
map.rotateTo(bearing, options?, eventData?)
用动画过渡将地图旋转到指定的方位角。方向角为0时,指向正北方向,90度的方位朝东。 支持AnimationOptions属性(后续再整理)。
Animate the camera along a path(3D)
实现思路:
(1)分别准备行走的路线数据和Camera观察的路线数据
(2)设置总的动画持续时间,根据当前时间与开始时间的间隔算出当前所处的阶段
(3)根据当前的阶段获取行走线段的当前点坐标和Camera观察的当前点坐标,从而通过FreeCamera API设置当前Camera的位置,并看向当前的行走坐标
function frame(time) {
if (!start) start = time;
// phase determines how far through the animation we are
var phase = (time - start) / animationDuration;
// phase is normalized between 0 and 1
// when the animation is finished, reset start to loop the animation
if (phase > 1) {
// wait 1.5 seconds before looping
setTimeout(function () {
start = 0.0;
}, 1500);
}
// use the phase to get a point that is the appropriate distance along the route
// this approach syncs the camera and route positions ensuring they move
// at roughly equal rates even if they don't contain the same number of points
var alongRoute = turf.along(
turf.lineString(targetRoute),
routeDistance * phase
).geometry.coordinates;
var alongCamera = turf.along(
turf.lineString(cameraRoute),
cameraRouteDistance * phase
).geometry.coordinates;
var camera = map.getFreeCameraOptions();
// set the position and altitude of the camera
camera.position = mapboxgl.MercatorCoordinate.fromLngLat(
{
lng: alongCamera[0],
lat: alongCamera[1]
},
cameraAltitude
);
// tell the camera to look at a point along the route
camera.lookAtPoint({
lng: alongRoute[0],
lat: alongRoute[1]
});
map.setFreeCameraOptions(camera);
window.requestAnimationFrame(frame);
}
window.requestAnimationFrame(frame);
Customize camera animations
1 自定义相机动画
// each function takes a parameter t that represents
// the progress of the animation.
// t is in a range of 0 to 1 where 0 is the initial
// state and 1 is the completed state.
var easingFunctions = {
// start slow and gradually increase speed
easeInCubic: function (t) {
return t * t * t;
},
// start fast with a long, slow wind-down
easeOutQuint: function (t) {
return 1 - Math.pow(1 - t, 5);
},
// slow start and finish with fast middle
easeInOutCirc: function (t) {
return t < 0.5
? (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2
: (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2;
},
// fast start with a "bounce" at the end
easeOutBounce: function (t) {
var n1 = 7.5625;
var d1 = 2.75;
if (t < 1 / d1) {
return n1 * t * t;
} else if (t < 2 / d1) {
return n1 * (t -= 1.5 / d1) * t + 0.75;
} else if (t < 2.5 / d1) {
return n1 * (t -= 2.25 / d1) * t + 0.9375;
} else {
return n1 * (t -= 2.625 / d1) * t + 0.984375;
}
}
};
2 animationOptions
与map.flyTo()
方法
var animationOptions = {
duration: duration,
easing: easingFn,
offset: [offsetX, offsetY],
animate: animate,
essential: true // animation will happen even if user has `prefers-reduced-motion` setting on
};
animationOptions.center = center;
map.flyTo(animationOptions);
Fly to a location based on scroll position
1 自定义各城市的相机参数
var chapters = {
'baker': {
bearing: 27,
center: [-0.15591514, 51.51830379],
zoom: 15.5,
pitch: 20
},
'aldgate': {
duration: 6000,
center: [-0.07571203, 51.51424049],
bearing: 150,
zoom: 15,
pitch: 0
},
'london-bridge': {
bearing: 90,
center: [-0.08533793, 51.50438536],
zoom: 13,
speed: 0.6,
pitch: 40
},
'woolwich': {
bearing: 90,
center: [0.05991101, 51.48752939],
zoom: 12.3
},
'gloucester': {
bearing: 45,
center: [-0.18335806, 51.49439521],
zoom: 15.3,
pitch: 20,
speed: 0.5
},
'caulfield-gardens': {
bearing: 180,
center: [-0.19684993, 51.5033856],
zoom: 12.3
},
'telegraph': {
bearing: 90,
center: [-0.10669358, 51.51433123],
zoom: 17.3,
pitch: 40
},
'charing-cross': {
bearing: 90,
center: [-0.12416858, 51.50779757],
zoom: 14.3,
pitch: 20
}
};
2 cameraOptions
与map.flyTo()
方法
map.flyTo(chapters[chapterName]);
Navigate the map with game-like controls
地图使用panBy
方法前后移动,easeTo
方法左右移动。
// pixels the map pans when the up or down arrow is clicked
var deltaDistance = 100;
// degrees the map rotates when the left or right arrow is clicked
var deltaDegrees = 25;
function easing(t) {
return t * (2 - t);
}
map.getCanvas().addEventListener('keydown', function (e) {
e.preventDefault();
if (e.which === 38) {
// up
map.panBy([0, -deltaDistance], {
easing: easing
});
} else if (e.which === 40) {
// down
map.panBy([0, deltaDistance], {
easing: easing
});
} else if (e.which === 37) {
// left
map.easeTo({
bearing: map.getBearing() - deltaDegrees,
easing: easing
});
} else if (e.which === 39) {
// right
map.easeTo({
bearing: map.getBearing() + deltaDegrees,
easing: easing
});
}
},
true
);
Offset the vanishing point using padding
利用map.easeTo()
方法的padding
属性控制地图的左右偏移。
var padding = {};
padding['left'] = 300;
map.easeTo({
padding: padding,
duration: 1000 // In ms, CSS transition duration property for the sidebar matches this value
});