项目(二):利用Leaflet.js实现瓦片图的显示

Show tile maps

Posted by AlbertWu on September 23, 2016

最近因为我们的svg地图惨遭dalao吐槽,所以开始研究地图的异步png加载方式,即将地图通过分层->切割的方式存储在服务器端,然后通过客户端的点击或者拖拽异步向服务器端发送请求。

展开步骤

1.瓦片图研究

什么是瓦片图?顾名思义,指瓦片形状的图片。但是它又有什么用呢?不知大家有没有注意过GooleMap、BaiduMap等在线地图供应商是如何将地图信息呈现给用户的?是直接将全幅地图像画布一样呈现给用户,然后用户通过拖拽直接可以查看到视图内画布的信息吗?其实不是的。你想想让服务端直接将所有图片信息发送给客户端+浏览器全图渲染+呈现给用户,需要多少的时间? 其实不然,就像3D游戏中GPU只渲染用户能看到的画面内的景象一样,服务器只会将用户能在浏览器里看到的区域的图片发送给客户端,异步按需加载图片。Wiki

  • 瓦片图的存储结构为z-x-y 即若该图所在位置为第z层(x,y),则其存储位置为z->x->y.png alt text

2.通过爬虫获得GoogleMap图片

Google存储切片地图的格式: http://mt2.google.cn/vt/lyrs=m@167000000&hl=zh-CN&gl=cn&x=?&y=?&z=? 可以看到图片存储对象由x、y、z的取值决定的。 所以我利用python的request库写正则表达式对需要的图片切块批量保存至本地。

#批量从googletilemap下载tile图片
import requests

z=3;
for i in range(z):
    for j in range(i):
        for k in range(i):
            content=requests.get('http://mt2.google.cn/vt/lyrs=m@167000000&hl=zh-CN&gl=cn&x='+str(2**j-1)+'&y='+str(2**k-1)+'&z='+str(i))
            f=open('x='+str(2**j-1)+'y='+str(2**k-1)+'z='+str(i)+'.jpg','wb')
            f.write(content.content)
            f.close()

3.经纬度与平面坐标转换

首先,我们需要认识到球形投影的方式(墨卡托投影),根据计算公式我们即可互相转化(x,y)的平面坐标和(θ,ψ)的经纬度坐标,公式文档

4.前端显示

这里我了解到常用的js库有LeafletOpenLayers,具体可见各自document。 如下我利用了Leaflet的开源库实现前端显示。

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<link href="css/leaflet.css" rel="stylesheet">
	<script src="js/leaflet.js"></script>
	<script src="js/leaflet-pip-v2.min.js"></script>
	<title>example for pointInLayer</title>
</head>
<style>
  body { margin:0; padding:0; }
  #map { position:absolute;height:100%;width:100%;background-color:#000000}
</style>
<body>
<div id="map"></div>
	<script>
		var map = L.map('map').setView([0,0],2);
		L.tileLayer('img/{z}/{x}/{y}.png',{minZoom:0,maxZoom:5,noWrap:true}).addTo(map);
	</script>
</body>
</html>

对tileMap的科普就这些吧,我继续去填自己无法把svg切png的锅……


Creative Commons License
This work is licensed under a CC A-S 4.0 International License.