视图控制与坐标转换
地图的「视图」由中心点与缩放级别决定。切换视图有四个方法,动画与精度各不相同; 坐标转换则负责在屏幕像素与经纬度之间来回换算。
四个切视图的方法
| 方法 | 行为 | 适用 |
|---|---|---|
setView(center, zoom) | 直接跳过去,无动画 | 初始化、恢复上次状态 |
panTo(center) | 平移动画,缩放不变 | 相邻位置之间移动 |
flyTo(center, zoom) | 缩放加平移的平滑动画,适合长距离 | 跨城市、跨区域的跳转 |
fitBounds(bounds) | 自动算出能装下范围的缩放级别 | 展示搜索结果、图层范围 |
var map = L.map('map').setView([39.907359, 116.391263], 11);
map.flyTo([31.230416, 121.473701], 12, {
duration: 2.2, // 秒
easeLinearity: 0.3
});
var region = L.latLngBounds([39.80, 116.20], [40.05, 116.55]);
map.fitBounds(region, {
padding: [30, 30], // 四边留白,像素
maxZoom: 14, // 防止小范围被放大过头
animate: true
});
fitBounds 不传 maxZoom 时,一个点或一条短线段可能被放大到
街道级别。业务上通常希望「最多到某个级别」,显式限制比事后判断更简单。
动画结束之后再做事
动画是异步的。在 flyTo 之后立刻读取 map.getCenter(),
拿到的是起点而不是终点。要等 moveend 或 zoomend。
function flyAndThen(target, zoom, done) {
map.once('moveend', function () {
done(map.getBounds());
});
map.flyTo(target, zoom);
}
flyAndThen([31.230416, 121.473701], 13, function (bounds) {
console.log('抵达', bounds.toBBoxString());
});
用 once 而不是 on:on 会一直保留监听,
多次调用后回调会叠加执行。
屏幕坐标与经纬度互转
自定义覆盖物、按像素做碰撞检测、判断点击落在哪个网格里,都依赖这两组方法。 Leaflet 提供三层坐标:
| 方法 | 输入 | 输出 |
|---|---|---|
latLngToContainerPoint | 经纬度 | 相对地图容器左上角的像素 |
containerPointToLatLng | 容器像素 | 经纬度 |
latLngToLayerPoint | 经纬度 | 相对图层原点的像素,随拖动变化 |
layerPointToLatLng | 图层像素 | 经纬度 |
project / unproject | 经纬度 / 平面坐标 | 当前缩放级别下的平面像素 |
map.on('click', function (e) {
var p = e.containerPoint; // 点击处像素
var ll = map.containerPointToLatLng(p); // 换回经纬度
var topLeft = map.containerPointToLatLng([0, 0]);
var bottomRight = map.containerPointToLatLng([
map.getSize().x, map.getSize().y
]);
console.log('点击', ll.lat, ll.lng);
console.log('视野', topLeft, bottomRight);
});
容器尺寸变化后必须通知地图
Leaflet 在初始化时读取一次容器尺寸,之后靠 resize 事件或手动调用更新。
侧边栏展开、全屏切换、标签页从隐藏变可见,都会让容器尺寸变化而 Leaflet 不知道,
表现是地图只占了左上角一块,或者拖动范围错位。
window.addEventListener('resize', function () {
map.invalidateSize();
});
// 容器从 display:none 变为可见后,等一帧再调用
document.getElementById('tab-map').addEventListener('click', function () {
requestAnimationFrame(function () {
map.invalidateSize({ pan: false });
});
});
invalidateSize({ pan: false }) 只重算尺寸、不平移中心,
适合「容器变大但希望保持视野中心」的场景。
注意事项
zoom 超出图层范围
瓦片图层有 minZoom 与 maxZoom,地图本身也有。
数据只到 18 级却允许放到 22 级,画面会变成放大的马赛克。
在 L.map 的选项里统一限制,比逐层设置更不易漏。
flyTo 与 setView 混用导致动画中断
动画未结束时调用 setView,旧动画会被直接掐断,
moveend 只触发一次。依赖「动画结束」的逻辑要放在事件里,
不要用 setTimeout 猜时间。
坐标系不是 WGS84 时转换会偏
上面所有转换都基于 Leaflet 的默认投影,输入必须是 WGS84 经纬度。 接了 GCJ-02 的瓦片又用 WGS84 坐标调用转换,像素与位置会整体错开数百米。
经纬志(2026)。《视图控制与坐标转换》。https://www.jingweizhi.com/leaflet/tutorial/view-control.html(访问日期 2026-11-03)。