概述
前段时间有个项目因为网络原因,需要再内网搭建一个地图,于是经过一个多星期的折腾,地图终于搭建完成,
这里我们地图图层的核心部分简单的介绍一下。网上也有专门的图层下载器,不过都是要收钱的,如果不想付钱,就可以根据原理自己下载即可。
离线地图
地图包括很多部分,其中图层是最基础的,其次是它js和css, 再次就是他们对应的地图数据,如: 我搜索“网吧”能把附件的网吧标注出来一样。
图层
图层就是常说的瓦片地图,一种多分辨率层次的模型,从瓦片金字塔的底层到顶层,分辨率越来越低,但表示的地理范围不变。
如图:
(图片来与百度百科)
我这里以百度地图为例:
我们仔细查看,我们发现百度地图也是一个一个的图片,通过CSS样式的排版控制来显示地图,当上一个图层在下一个图层中又是4个图片, 就这样一层一层的, 一共1 ~ 19层
同时我们也能发现,图片是一个连着一个的,我们注意到每个图片都是这么一个个链接:
https://ss1.bdstatic.com/8bo_dTSlR1gBo1vgoIiO_jowehsv/tile/?qt=vtile&x=815&y=214&z=12&styles=pl&udt=20190425&scaler=1&showtext=0
https://ss0.bdstatic.com/8bo_dTSlR1gBo1vgoIiO_jowehsv/tile/?qt=vtile&x=815&y=213&z=12&styles=pl&udt=20190425&scaler=1&showtext=0
其中,x=815&y=214&z=12 就是我们的图片坐标,
X - 横坐标
Y - 纵坐标
Z - 图层
ss1.bdstatic.com, ss2.bdstatic.com 等就是服务器集群的域名。
所以,这样我们就可以知道, 我们如果下载图层,我们只需要知道图层的坐标即可下载。那么图层的坐标是如何计算得到呢?
百度图层算法
关于图层的算法,我大致介绍下,具体的算法还是查专业资料,O(∩_∩)O哈哈~...
如图:
因为地球是园的,地图是平面的,所以就有一个转换过程,叫什么墨卡托投影(具体查专业资料),大致意思是假想一个与地轴方向一致的圆柱切或割于地球,按等角条件,将经纬网投影到圆柱面上,将圆柱面展为平面。
平面后我们就可以通过 横坐标、纵坐标,来计算点的距离,然后在换算为像素坐标。具体算法示例如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>地图坐标概念</title>
<script src="http://api.map.baidu.com/api?v=2.0&ak=GVehn0frGnwbDWjRPxGI6GR4rmfqw7DG"></script>
</head>
<body>
<div id="map_container" style="width: 500px; height: 320px;"></div>
<script>
var map = new BMap.Map('map_container', {
defaultCursor : 'default'
});
// 设置中心点
map.centerAndZoom(new BMap.Point(120.035641, 30.246635), 17);
var TILE_SIZE = 256;
// 点击一个坐标点,返回对应的坐标
map.addEventListener('click', function(e) {
var info = new BMap.InfoWindow('', {
width : 260
});
var projection = this.getMapType().getProjection();
var lngLat = e.point;
var lngLatStr = "经纬度:" + lngLat.lng + ", " + lngLat.lat;
var worldCoordinate = projection.lngLatToPoint(lngLat);
var worldCoordStr = "<br />平面坐标:" + worldCoordinate.x + ", " + worldCoordinate.y;
var pixelCoordinate = new BMap.Pixel(Math.floor(worldCoordinate.x * Math.pow(2, this.getZoom() - 18)),
Math.floor(worldCoordinate.y * Math.pow(2, this.getZoom() - 18)));
var pixelCoordStr = "<br />像素坐标:" + pixelCoordinate.x + ", "
+ pixelCoordinate.y;
var tileCoordinate = new BMap.Pixel(Math.floor(pixelCoordinate.x / 256), Math.floor(pixelCoordinate.y / 256));
var tileCoordStr = "<br />图块坐标:" + tileCoordinate.x + ", " + tileCoordinate.y;
var viewportCoordinate = map.pointToPixel(lngLat);
var viewportCoordStr = "<br />可视区域坐标:" + viewportCoordinate.x
+ ", " + viewportCoordinate.y;
var overlayCoordinate = map.pointToOverlayPixel(lngLat);
var overlayCoordStr = "<br />覆盖物坐标:" + overlayCoordinate.x + ", "
+ overlayCoordinate.y;
info.setContent(lngLatStr + worldCoordStr + pixelCoordStr
+ tileCoordStr + viewportCoordStr + overlayCoordStr);
map.openInfoWindow(info, lngLat);
});
</script>
</body>
</html>
天地图图层算法
天地图原理也类似, 其坐标点和图层的算法如下:
package com.topinfo.tdt;
/**
* @ClassName: Test2
* @Description: 根据坐标获取对应的瓦片行、列
* @author: 杨攀
* @date: 2019年2月20日 下午2:00:46
* @Copyright: 2019 www.tuxun.net Inc. All rights reserved.
*/
public class Test2 {
public static void main(String[] args){
int level = 18;
//左上角经纬度
double leftTop_lon = 115.422051;
double leftTop_lat = 40.978643;
//右下角经纬度
double rightBotton_lon = 117.383319;
double rightBotton_lat = 39.455766;
System.out.println (getTileNumber (leftTop_lat, leftTop_lon, level));
System.out.println (getTileNumber (rightBotton_lat, rightBotton_lon, level));
}
public static String getTileNumber(final double lat,final double lon,final int level){
int xtile = (int) Math.floor ((lon + 180) / 360 * (1 << level));
int ytile = (int) Math.floor ((1 - Math.log (Math.tan (Math.toRadians (lat)) + 1 / Math.cos (Math.toRadians (lat))) / Math.PI) / 2 * (1 << level));
if (xtile < 0) xtile = 0;
if (xtile >= (1 << level)) xtile = ((1 << level) - 1);
if (ytile < 0) ytile = 0;
if (ytile >= (1 << level)) ytile = ((1 << level) - 1);
return (xtile + "/" + ytile);
}
}
下载使用
下载图层
原理我们懂了, 其实就是把你要下载的地图左上角、和右下角坐标拿到,然后两个for循环即可。
比如:我们 下载杭州的 地图, 我们先通过地图提供的获取行政区划API, 一般都会有地图的左上角、和右下角的坐标,比如: 天地图
它这里的四个角其实就是 左上角、和右下角的坐标,不信你们可以直接试试, 知道左上角、和右下角的坐标后,通过上面的算法,计算出左上角、和右下角的图层在Z层的X、Y的坐标,剩下的就是下一个下载方法进行下载了,可以写一个下载连接池进行下载。
在下载的时候,这里给出两个建议:
1、 把最后一层(百度是19层,天地图是18层)单独线程下载,其他的层单独线程下载,最后一层非常大。
2、 下载太多的话,最好别在公司下,否则别人以为你是在攻击,会禁用你们公司的IP,会导致你们公司后面无法访问地图,需要跟他们客户沟通才能解禁,O(∩_∩)O哈哈~~
竟然不能提交附件,我放到百度网盘了:
链接: https://pan.baidu.com/s/1nyix... 提取码: 8ttf 复制这段内容后打开百度网盘手机App,操作更方便哦
网盘中包括
1、百度的离线js和算法demo, 不包括下载的方法,自己实现一个即可。
2、天地图的图层下载示例,因为我们只是一锤子买卖,平常几乎不会离线地图,各位可以优化性能,可以修改为多线程的下载,可以字符串连接等,优化你们自己处理啊,我只是抛砖引玉一下。不包括离线的js, 离线js改起来也简单的。
修改JS的离线
百度的JS离线,网上有很多,我们只需要下载稍微修改下,见上面的网盘链接。
天地图JS离线就相对比较麻烦,我也是断断续续修改了好几天才修改好,需要注意我们在测试离线的时候,先把网络断了,清空浏览器缓存(这步很重要,因为有些是缓存到locaStorage中),然后在测试,把报错的地方统统修改掉,或者把需要用到的js,css提前下载到本地,然后本地引用即可,
具体代码JS我就不传了,因为都比较简单,只要细心都不是问题的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。