Leaflet中如何限制地图的拖动范围

举报
夜郎king 发表于 2025/10/02 11:03:22 2025/10/02
【摘要】 本文讲解了在Leaflet中如何进行地图范围的控制,并通过代码的方式进行示例,并展示了最终效果。

一、背景

       在Leaflet默认的地图载模式中,假如没有对地图的一个范围进行限制,那就会带来一个问题,随着地图可以拖动,当地图往右拖动越多,每跨一屏(这里的一屏指地图投影后在页面上的平铺位置)经度会加360度。同理,如果往左边拖一屏,也是相应的嫌少-360度。这是目标点的一个定位问题。

        第二个问题是,假如我们在,[120.146484,29.649869]这个点标一个marker,你会发现,当拖动一屏后,它并没有在同一个位置也标上这个点。如果把此时的地图给用户看的话,肯定会产生一种错觉。

二、问题展示

      1、经度大于180度的场景

        使用鼠标拖拽地图到右边,使用鼠标选点展示坐标可以看到,此时坐标的经度468.984375,明显超出了正常经度的范围值。   

1.jpg

2、经度小于-180度的场景

        使用鼠标拖拽地图到左边,使用鼠标选点展示坐标可以看到,此时坐标的经度 -241.171875,明显超出了正常经度的范围值。 

1.jpg

3、marker标错

        使用如下代码进行一个marker的标定,你会发现,无论将地图往左边拖或者右边拖,地图上始终只有一个点。

L.marker([22.024546, 110.654297]).addTo(mymap)
		.bindPopup("<b>Hello world!</b><br />我是一个提示框.").openPopup();

1.jpg

 三、原因分析

        造成以上问题的原因是什么呢?众所周知,在地理信息系统中,对地理范围是有一个明确的定义的。经度范围是0-180°,纬度范围是0-90°。从0°经线算起,向东、向西各分作180°,以东的180°属于东经,习惯上用“百E”作代号,以西的180°属于西经,习惯上用“W”作代号。我们通常说的纬度度指的是大地纬度。其数值在0至90度之间。位于赤道以北的点的纬度叫北纬,记为N;位于赤道以南的点的纬度称南纬,记为S。为了研究问题方便,人们把纬度分问为低、 中、高纬度。0°~30°为低纬度, 30°~ 60°为中纬度, 60~90°为高答纬度。


1.jpg

1.jpg

了解了上述的知识后就知道了解决上述问题的办法,只需要在Leaflet中定义地图时,限制以下地图的经纬度范围。

四、Leaflet API

      通过查找Leaflet的api我们发现了,在地图参数中有以下的定义:

1.jpg

   默认的情况下,maxBounds参数设置为空。设置此选项后,地图会将视图限制在给定的地理范围内,如果用户试图在视图之外平移,则将用户弹回。要动态设置限制,请使用 setMaxBounds方法。通过这种方式就能限制地图的最大范围。

五、代码实现

1、leaflet资源引入

<head>
	<title>经纬度投影-限制地图拖动范围</title>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
	<link rel="stylesheet" href="/2d/leaflet/leaflet.css" />
    <script src="/2d/leaflet/leaflet.js?v=1.0.0"></script>
</head>

​2、地图定义

L.CRS.CustomEPSG4326 = L.extend({}, L.CRS.Earth, {
		code: 'EPSG:4326',
		projection: L.Projection.LonLat,
		transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5),
		scale: function (zoom) {
			return 256 * Math.pow(2, zoom - 1);
		}
	});

// 第一种设置方式,可行
//限制地图的拖动范围是正负90到正负180,这样才合理。
var corner1 =  L.latLng(-90, -180); //设置左上角经纬度
var corner2 = L.latLng(90, 180);	//设置右下点经纬度
var bounds = L.latLngBounds(corner1, corner2); //构建视图限制范
var mymap = L.map('mapid',{crs:L.CRS.CustomEPSG4326,maxBounds:bounds}).setView([29.052934, 104.0625], 5);

这里的关键代码就是如下代码,通过这两个位置来限制拖动情况。地图的定义在crs这里,我使用了一个自己的转换规则,这取决你的瓦片读取方式。如果标准的WGS84投影,可以不需要这么定义,直接使用默认的方式加载即可。

var corner1 =  L.latLng(-90, -180); //设置左上角经纬度
var corner2 = L.latLng(90, 180);	//设置右下点经纬度
var bounds = L.latLngBounds(corner1, corner2); //构建视图限制范围

除了使用这种初始定义的方式,还可以使用setMaxBounds(args)这种函数调用来进行,效果是一样的,调用代码:mymap.setMaxBounds(bounds);这种方式对控制显得更灵活方便。

3、完整代码实例

<!DOCTYPE html>
<html>
<head>
	<title>经纬度投影-限制地图拖动范围</title>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
	<link rel="stylesheet" href="/2d/leaflet/leaflet.css" />
    <script src="/2d/leaflet/leaflet.js?v=1.0.0"></script>
</head>
<body>
<div id="mapid" style="width: 100%; height: 600px;"></div>
<script>

    L.CRS.CustomEPSG4326 = L.extend({}, L.CRS.Earth, {
		code: 'EPSG:4326',
		projection: L.Projection.LonLat,
		transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5),
		scale: function (zoom) {
			return 256 * Math.pow(2, zoom - 1);
		}
	});

    // 第一种设置方式,可行
    //限制地图的拖动范围是正负90到正负180,这样才合理。
	/*var corner1 =  L.latLng(-90, -180); //设置左上角经纬度
    var corner2 = L.latLng(90, 180);	//设置右下点经纬度
    var bounds = L.latLngBounds(corner1, corner2); //构建视图限制范围
	var mymap = L.map('mapid',{crs:L.CRS.CustomEPSG4326,maxBounds:bounds}).setView([29.052934, 104.0625], 5);*/

	var corner1 =  L.latLng(-90, -180); //设置左上角经纬度
    var corner2 = L.latLng(90, 180);	//设置右下点经纬度
    var bounds = L.latLngBounds(corner1, corner2); //构建视图限制范围
	var mymap = L.map('mapid',{crs:L.CRS.CustomEPSG4326}).setView([29.052934, 104.0625], 5);
    
	//第二种设置方式,可行
	//mymap.setMaxBounds(bounds);

	L.tileLayer('http://localhost:8086/data/basemap_nowater/1_10_tms/{z}/{x}/{y}.jpg', {
		maxZoom: 16,
		attribution: 'yelangkingMap data &copy; <a href="https://www.openstreetmap.org/">本地瓦片加载</a> contributors, ' +
			'<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
			'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
		id: 'mapbox/streets-v11',
		tileSize: 256,
		zoomOffset: -1
	}).addTo(mymap);

	//标签
	L.tileLayer('http://localhost:8086/data/basemap_nowater/1-10label/{z}/{x}/{y}.png', {maxZoom: 10,minZoom:3,
		id: 'mapbox/label',tileSize: 256,zoomOffset: -1
	}).addTo(mymap);

	L.marker([22.024546, 110.654297]).addTo(mymap)
		.bindPopup("<b>Hello world!</b><br />我是一个提示框.").openPopup();

	L.circle([29.649869, 120.146484], 99000, {
		color: 'red',
		fillColor: '#f03',
		fillOpacity: 0.5
	}).addTo(mymap).bindPopup("我是一个圆.");

	L.polygon([
		[32.916485, 101.601563],
		[30.562261, 105.556641],
		[34.524661, 108.149414]
	]).addTo(mymap).bindPopup("我是一个多边形.");

	var popup = L.popup();

	function onMapClick(e) {
		popup.setLatLng(e.latlng)
			.setContent("当前坐标为:" + e.latlng.toString())
			.openOn(mymap);
	}
	mymap.on('click', onMapClick);
</script>
</body>
</html>

六、最终效果

       最终我们可以在界面上看到,当你想拖动地图到左边或者右边时,地图会默认弹回。这样就合理的避免了坐标太大超出范围的问题,以及点在地图上的标定问题。

1.jpg

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。