最近因为我们的svg地图惨遭dalao吐槽,所以开始研究地图的异步png加载方式,即将地图通过分层->切割的方式存储在服务器端,然后通过客户端的点击或者拖拽异步向服务器端发送请求。
展开步骤
- 瓦片图研究
- 通过爬虫获得瓦片图 地址命名规则
- 经纬度与平面坐标转换
- 前端显示
1.瓦片图研究
什么是瓦片图?顾名思义,指瓦片形状的图片。但是它又有什么用呢?不知大家有没有注意过GooleMap、BaiduMap等在线地图供应商是如何将地图信息呈现给用户的?是直接将全幅地图像画布一样呈现给用户,然后用户通过拖拽直接可以查看到视图内画布的信息吗?其实不是的。你想想让服务端直接将所有图片信息发送给客户端+浏览器全图渲染+呈现给用户,需要多少的时间? 其实不然,就像3D游戏中GPU只渲染用户能看到的画面内的景象一样,服务器只会将用户能在浏览器里看到的区域的图片发送给客户端,异步按需加载图片。Wiki
- 瓦片图的存储结构为z-x-y 即若该图所在位置为第z层(x,y),则其存储位置为z->x->y.png
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库有Leaflet和OpenLayers,具体可见各自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的锅……
This work is licensed under a CC A-S 4.0 International License.