沿路径点动画
使用Turf沿线路平滑地为点设置动画;
<!DOCTYPE html>
<html lang="en">
<head>
<title>沿路径点动画</title>
<meta property="og:description" content="使用Turf沿线路平滑地为点设置动画" />
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.5.0/dist/maplibre-gl.css' />
<script src='https://unpkg.com/maplibre-gl@5.5.0/dist/maplibre-gl.js'></script>
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
const map = new maplibregl.Map({
container: 'map',
style:
'https://demotiles.maplibre.org/styles/osm-bright-gl-style/style.json',
center: [-96, 37.8],
zoom: 3
});
// 将点添加到地图
map.on('load', () => {
// 添加源和图层
map.addSource('route', {
'type': 'geojson',
'data': {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[-122.483696, 37.833818],
[-112.073844, 36.057982],
[-93.215332, 37.972775],
[-84.516602, 39.097755],
[-71.355469, 42.379482]
]
}
}
});
map.addSource('point', {
'type': 'geojson',
'data': {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Point',
'coordinates': [-122.483696, 37.833818]
}
}
});
map.addLayer({
'id': 'route',
'source': 'route',
'type': 'line',
'paint': {
'line-width': 2,
'line-color': '#007cbf'
}
});
map.addLayer({
'id': 'point',
'source': 'point',
'type': 'circle',
'paint': {
'circle-radius': 10,
'circle-color': '#007cbf'
}
});
// 获取路线坐标
const route = {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[-122.483696, 37.833818],
[-112.073844, 36.057982],
[-93.215332, 37.972775],
[-84.516602, 39.097755],
[-71.355469, 42.379482]
]
}
};
// 计算路线长度
const lineDistance = turf.length(route);
const arc = [];
// 将路线划分为100个步骤,为每个步骤的点创建一个特征
// 使用Turf.js的along方法在各点之间创建弧线
const steps = 500;
for (let i = 0; i < lineDistance; i += lineDistance / steps) {
const segment = turf.along(route.geometry, i);
arc.push(segment.geometry.coordinates);
}
route.geometry.coordinates = arc;
// 用新的弧线路径更新路线
map.getSource('route').setData(route);
// 为路线动画设置计数器
let counter = 0;
function animate() {
// 更新点的位置
const start =
route.geometry.coordinates[
counter >= steps ? counter - 1 : counter
];
map.getSource('point').setData({
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Point',
'coordinates': start
}
});
// 如果是路线的最后一点,就重置计数器
if (counter < steps) {
counter = counter + 1;
} else {
counter = 0;
}
// 请求下一帧动画
requestAnimationFrame(animate);
}
// 开始动画
animate();
});
</script>
</body>
</html>