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

49 篇文章 16 订阅
40 篇文章 6 订阅

一、背景

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

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

二、问题展示

      1、经度大于180度的场景

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

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

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

      3、marker标错

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

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

 三、原因分析

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

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

四、Leaflet API

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

maxBoundsLatLngBoundsnullWhen this option is set, the map restricts the view to the given geographical bounds, bouncing the user back if the user tries to pan outside the view. To set the restriction dynamically, use setMaxBounds method.

        默认的情况下,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>

六、最终效果

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

  • 90
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 204
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 204
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜郎king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值