1.加载离线地图
Demo工程文件百度网盘下载: baidumapv2.0_js_offline_V1_V1.0.0.rar
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>百度离线版2.0 DEMO</title> <script type="text/javascript" src="js/apiv2.0.min.js"></script> <link rel="stylesheet" type="text/css" href="css/bmap.css"/> </head> <body> <div style="width:520px;height:340px;border:1px solid gray" id="container"></div> </body> </html> <script type="text/javascript"> // 百度地图API功能 var map = new BMap.Map("container"); //创建Map实例 map.centerAndZoom(new BMap.Point(118.00323, 36.81635), 13); //初始化地图,设置中心点坐标和地图级别 //map.addControl(new BMap.MapTypeControl()); //添加地图类型控件 离线只支持电子地图,卫星/三维不支持 //map.setCurrentCity("北京"); //设置地图显示的城市 离线地图不支持 map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放 map.addControl(new BMap.NavigationControl()); //缩放按钮 </script>

2.获取地图瓦片
2.1 瓦片存放规则
离线地图是由一张张256×256的图片拼接而成的,同一地点在每一级缩放下的坐标都不同,缩放越大坐标值也越大。
读取离线瓦片的规则在文件夹命名中有所体现,../tiles/13/1605/532.png代表缩放层级为13级,x=1605,y=532的瓦片。
百度存放这些贴片的url为
http://online3.map.bdimg.com/onlinelabel/?qt=tile&x=%d&y=%d&z=%d&styles=pl&udt=20180321&scaler=1&p=1
所以只需要请求贴片对应的url,下载下来,按照坐标规则分文件夹存放就行了。
2.2 瓦片坐标获取
这是关键和难点所在,我参考了 百度地图API详解之地图坐标系统 - jz1108 - 博客园 的方法。
原博中实现了点击地图上的点,显示经纬度和瓦片坐标等信息,但点击一次只能显示所处一个层级的瓦片坐标。
因为同一个点的经纬度是始终不变的,所以可以在点击一次之后获取到此点的经纬度坐标,再利用经纬度进行i=3;i<20;i++的循环请求(百度地图层级为3-19),已经能实现点击一次得到此点所有层级的瓦片坐标了。
那么要实现的离线地图必定是一个区域,可以用两个点确定(左下和右上,东经北纬右上坐标为区域上限,左下为下限)
得到这些瓦片坐标后,需要拼接出url进行下载并归类命名,查了很多资料没有发现js的实现方法,想办法用python实现..
python无法直接获取到console中输出的内容,只能想办法用js直接输出txt文件就可以了。
查了很久发现了一个方法 利用Javascript生成txt文本文件 - CSDN博客
js代码
<script> function tilexy(x,y){ var xs = '';var ys = '' for (var i=3;i<20;i++){ var map =new BMap.Map('map_container2', {defaultCursor: 'default'}); map.centerAndZoom(new BMap.Point(118.003, 36.816), i); var TILE_SIZE =256; var projection =map.getMapType().getProjection(); var worldCoordinate = projection.lngLatToPoint(new BMap.Point(x, y)); var pixelCoordinate =new BMap.Pixel(Math.floor(worldCoordinate.x * Math.pow(2, map.getZoom() -18)), Math.floor(worldCoordinate.y * Math.pow(2, map.getZoom() -18))); var tileCoordinate =new BMap.Pixel(Math.floor(pixelCoordinate.x /256), Math.floor(pixelCoordinate.y /256)); var tileCoordStr ="坐标:"+ tileCoordinate.x +", "+ tileCoordinate.y; console.log(i +","+ tileCoordinate.x +","+ tileCoordinate.y); xs = xs + tileCoordinate.x+" ";ys = ys + tileCoordinate.y+" "; }; var blob = new Blob([xs+'\r\n'+ys], {type: "text/plain;charset=utf-8"}); saveAs(blob, "xys.txt"); }; </script>
<script> var map =new BMap.Map('map_container1', {defaultCursor: 'default'}); map.centerAndZoom(new BMap.Point(118.003, 36.816), 11); map.enableScrollWheelZoom(); var TILE_SIZE =256; map.addEventListener('click', function(e){ var projection =this.getMapType().getProjection(); var lngLat = e.point; var lngLatStr ="经纬度:"+ lngLat.lng +", "+ lngLat.lat; tilexy(lngLat.lng,lngLat.lat); }); </script>
2.3 瓦片下载存放
得到瓦片坐标剩下的就很简单了,完全变成了python爬虫的问题
python代码
import urllib.request import os #创建文件夹 def mkdir(path): folder = os.path.exists(path) if not folder: os.makedirs(path) #此文件所在目录 dirpath = os.getcwd().replace('\\','/') print('-----------------Py地图瓦片下载器------------------') print('') print('') print(' Powerd by SDUTzcz') print('') #设置需要的地图层级 a = input('最小层级[>=3]:') b = input('最大层级[<=19]:') #调取js获取到的瓦片坐标 with open('xys.txt','r',encoding='utf-8') as f1: mintile = f1.read().encode('utf-8').decode('utf-8-sig').split() with open('xys (1).txt','r',encoding='utf-8') as f2: maxtile = f2.read().encode('utf-8').decode('utf-8-sig').split() #按坐标规则分文件夹下载瓦片 for z in range(int(a),int(b)+1): mkdir('./tiles/'+str(z)) for x in range(int(mintile[z-3]),int(maxtile[z-3])+1): mkdir('./tiles/'+str(z)+'/'+str(x)) for y in range(int(mintile[z-3+17]),int(maxtile[z-3+17])+1): urllib.request.urlretrieve('http://online3.map.bdimg.com/onlinelabel/?qt=tile&x=%d&y=%d&z=%d&styles=pl&udt=20180321&scaler=1&p=1'%(x,y,z),dirpath+'/tiles/%d/%d/%d.png'%(z,x,y))
本文作者为zcz,转载请注明。