vue集合离线百度地图
一、需求场景
所谓离线,大概都是项目在内网中使用,无法连接外网,所以需要开发离线地图功能。
在看以下步骤前,先提示这个vue项目是vue-cli生成的
二、开发步骤
1、通过API下载百度接口JS
打开会看到以下内容
在代码中找到src=http://api.map.baidu.com/getscript?v=3.0&ak=biuHZmoAow03mjwThwt8f2whaf4mVdHf&services=&t=20191018171908
打开src里的链接,就可以获得百度api的js代码
2、js代码清洗,保存
在在线JSON校验工具,将上面的代码,格式化,以便下面查看与修改。
然后新建js文件,将格式化后的代码粘贴进去,命名为baidu-api.js
再然后将此js文件放在vue项目中,我的放在了static下
最后,在vue项目的启动入口index.html的head中引入这个js
3、修改API文件
3.1、在baidu-api.js文件中,用Math.random()全局查找几次,定位到以下代码位置:
(以下代码会在百度更新有些出入,但基本样式不变,找相似)
function pa(a, b) { if (b) { var c = (1E5 * Math.random()).toFixed(0); D._rd["_cbk" + c] = function(a) { b && b(a); delete D._rd["_cbk" + c] }; a += "&callback=BMap._rd._cbk" + c } var e = O("script", { type: "text/javascript" }); e.charset = "utf-8"; e.src = a; e.addEventListener ? e.addEventListener("load", function(a) { a = a.target; a.parentNode.removeChild(a) }, t) : e.attachEvent && e.attachEvent("onreadystatechange", function() { var a = window.event.srcElement; a && ("loaded" == a.readyState || "complete" == a.readyState) && a.parentNode.removeChild(a) }); setTimeout(function() { document.getElementsByTagName("head")[0].appendChild(e); e = s }, 1) };
到此步,默认你已找到!!!
然后修改上面的代码,对HTTP拦截,不进行外部访问,只需在最开始添加一行:
if (/^http/.test(a)) return;
就是如下样式
function pa(a, b) { ////// if (/^http/.test(a)) return; // !!!!!这里加判断,如果是调用外部资源就退出去 ////// if (b) { var c = (1E5 * Math.random()).toFixed(0); D._rd["_cbk" + c] = function(a) { b && b(a); delete D._rd["_cbk" + c] }; a += "&callback=BMap._rd._cbk" + c } var e = O("script", { type: "text/javascript" }); e.charset = "utf-8"; e.src = a; e.addEventListener ? e.addEventListener("load", function(a) { a = a.target; a.parentNode.removeChild(a) }, t) : e.attachEvent && e.attachEvent("onreadystatechange", function() { var a = window.event.srcElement; a && ("loaded" == a.readyState || "complete" == a.readyState) && a.parentNode.removeChild(a) }); setTimeout(function() { document.getElementsByTagName("head")[0].appendChild(e); e = s }, 1) };
3.2、设置引用本地资源路径
在baidu-api.js文件中,用url.domain.main_domain_cdn.baidu[0]
全局多查找几次,定位到下面的代码:
D.Nt = window.HOST_TYPE || "0"; D.url = D.I_[D.Nt]; D.Uo = D.url.proto + D.url.domain.baidumap + "/"; D.Cd = D.url.proto + ("2" == D.Nt ? D.url.domain.main_domain_nocdn.other : D.url.domain.main_domain_nocdn.baidu) + "/"; D.oa = D.url.proto + ("2" == D.Nt ? D.url.domain.main_domain_cdn.other[0] : D.url.domain.main_domain_cdn.baidu[0]) + "/"; D.Ri = D.url.proto + D.url.domain.main_domain_cdn.webmap[0] + "/";
然后将
D.Ri = D.url.proto + D.url.domain.main_domain_cdn.webmap[0] + “/”
改为 D.Ri = ” :
如下样式:
D.Nt = window.HOST_TYPE || "0"; D.url = D.I_[D.Nt]; D.Uo = D.url.proto + D.url.domain.baidumap + "/"; D.Cd = D.url.proto + ("2" == D.Nt ? D.url.domain.main_domain_nocdn.other : D.url.domain.main_domain_nocdn.baidu) + "/"; D.oa = D.url.proto + ("2" == D.Nt ? D.url.domain.main_domain_cdn.other[0] : D.url.domain.main_domain_cdn.baidu[0]) + "/"; /////// D.Ri = ''; /////// D.Yh = function(a, b) { var c, e, b = b || "";
3.3、下载本地资源
所谓本地资源,就是在使用地图时需要用到的一些模块(module),比如图层类,标记类,控件类。
当你在地图中用到这些模块时,它会自动加载,因此我们需要先把这些模块的js文件下载下来,保存到本地。
这些模块有几十个之多,我们这里并不都存本地,而是用到哪个下载哪个,那么如何知道用到了哪个模块呢?
首先,在 baidu-api.js 文件中,用 &mod= 定位到下面的代码,然后加一行代码将用到的模块打印出来:
load: function(a, b, c) { var e = this.lb(a); if (e.Ke == this.tj.Bp) c && b(); else { if (e.Ke == this.tj.BF) { this.nJ(a); this.EM(a); var f = this; f.OB == t && (f.OB = p, setTimeout(function() { for (var a = [], b = 0, c = f.Pd.Vm.length; b < c; b++) { var e = f.Pd.Vm[b], n = ""; ja.Zx.iJ(e) ? n = ja.Zx.get(e) : (n = "", a.push(e + "_" + Tb[e])); f.Pd.qv.push({ VL: e, UD: n }) } f.OB = t; f.Pd.Vm.length = 0; //!!!!!!!!!!!!!!!!!!!! console.log("打印所需模块"); console.log(a); //!!!!!打印所需模块,这很重要 //!!!!!!!!!!!!!!!!!!!! //0 == a.length ? f.XJ() : pa(f.tF.$O + "&mod=" + a.join(",")) //////引用本地下载好的模块文件资源 if( a.length > 0 ){ for(let i=0; i<a.length;i++){ let mf = './static/modules/'+a[i]+'.js'; pa( mf ); console.log('加载模块文件:'+mf); //IE error } } else { f.XK() } ////// }, 1)); e.Ke = this.tj.RO }
然后,我们在需要使用地图的vue页面里,按照官方文档正常使用:
<template> <div id='MapBox'> <div class='baiduMap' id='mapShow' ref="mapShow"></div> </div> </template> <script> export default { name:'baiduMap', data() { return{ map: undefined, overView: undefined, marker: undefined, BMap: undefined, } }, methods:{ baiduMap(){ debugger this.BMap = BMap; // 创建地图实例 this.map = new BMap.Map("mapShow"); // 创建点坐标 let point = new BMap.Point(118.8035, 32.0658); //创建标注 this.marker=new BMap.Marker(point); //缩略地图控件。 this.overView=new BMap.OverviewMapControl({isOpen: true}); //添加控件 this.map.addControl(this.overView); //添加一个标注 this.map.addOverlay(this.marker); // 初始化地图,设置中心点坐标和地图级别 this.map.centerAndZoom(point, 12); //this.map.setCurrentCity("南京"); //开启鼠标滚轮缩放 this.map.enableScrollWheelZoom(true); } }, mounted(){ this.$nextTick(() => { this.baiduMap(); }) } } </script> <style> #MapBox { width: 100%; height: 100%; padding: 10px; position: relative; } /* 地图 */ .baiduMap{ height: 100%; width: 100%; } /* 去除地图上,左下字体标注 */ .anchorBL{ display:none; } </style>
特别注意:如果你要在进入页面就初始化地图,最好像上面那样,放在 mounted 生命函数的 this.$nextTick(() => {})里,以确保地图容器 #mapShow 元素渲染完成,不然有可能因为初始化时地图容器还未渲染而报错:
从上继续:
刷新这个vue页,关注控制台,就能看到要实现这些地图功能所需要的模块名,是个数组集合,如下图,我这里需要以下十一个模块:
下载api依赖模块的地址
通过上面的地址,只需要更换mod后面的值就可以找到需要的模块
然后在static下建一个modules文件夹来存放即将下载的模块文件
然后新建以打印出的模块为命名的js,将通过地址搜索到的js复制到此js文件里。这样模块文件就下载好了。
3.4、引用本地资源
在上面打印模块名的地方,做如下修改:
load: function(a, b, c) { var e = this.lb(a); if (e.Ke == this.tj.Bp) c && b(); else { if (e.Ke == this.tj.BF) { this.nJ(a); this.EM(a); var f = this; f.OB == t && (f.OB = p, setTimeout(function() { for (var a = [], b = 0, c = f.Pd.Vm.length; b < c; b++) { var e = f.Pd.Vm[b], n = ""; ja.Zx.iJ(e) ? n = ja.Zx.get(e) : (n = "", a.push(e + "_" + Tb[e])); f.Pd.qv.push({ VL: e, UD: n }) } f.OB = t; f.Pd.Vm.length = 0; //!!!!!!!!!!!!!!!!!!!! console.log("打印所需模块"); console.log(a); //!!!!!打印所需模块,这很重要 //!!!!!!!!!!!!!!!!!!!! //0 == a.length ? f.XJ() : pa(f.tF.$O + "&mod=" + a.join(",")) //////引用本地下载好的模块文件资源 if( a.length > 0 ){ for(let i=0; i<a.length;i++){ let mf = './static/modules/'+a[i]+'.js'; pa( mf ); console.log('加载模块文件:'+mf); //IE error } } else { f.XK() } ////// }, 1));
现在就能成功加载模块资源了。
这里要注意路径问题,如果路径不对,找不到模块文件,会报错:
三、加载瓦片改为本地离线瓦片
离线瓦片可以理解为地图离线包,没有它,离线地图无法显示的。
1、瓦片嵌入在项目中引用
1.1、下载瓦片
网上提供了水经注或者太乐地图下载器下载瓦片,介绍我用的太乐
太乐地图下载器
选择百度
下载 -> 选择行政区划,选完了之后该区域就会出现ufo图标
点击图标,选择 地图:
选择直接保存瓦片后,存储标准选择百度瓦片,存储格式会自动选择 .png。然后选择级别之后确定即可:
级别就是调用百度地图api处设置的缩放级别:
下载完成后可在这里查看:
找到存储目录:我这里下载了重庆12级的瓦片,所有的瓦片就存储在了12这个文件夹下
将所有瓦片文件夹整个复制到项目static/tiles目录下
你会发现除了下载了12级,还下载了9、10、11级,因为离线的关系,在地图上进行缩放操作到11级,但是如果没有11级的瓦片,地图就什么都不显示。所以如果想要缩放多少级,这些级别的瓦片必须都下载到本地。
1.2、瓦片配置文件
static目录下新建mp_load.js文件,定义瓦片路径及瓦片格式即地图api的主目录:
我们的瓦片是png格式的:
var bmapcfg = { 'imgext' : '.png', //瓦片图的后缀 根据需要修改,一般是 .png .jpg 'tiles_dir' : '', //普通瓦片图的地址,为空默认在tiles/ 目录 }; var scripts = document.getElementsByTagName("script"); var JS__FILE__ = scripts[scripts.length - 1].getAttribute("src"); //获得当前js文件路径 bmapcfg.home = JS__FILE__.substr(0, JS__FILE__.lastIndexOf("/")+1); //地图API主目录
然后在API文件之前引入该配置文件:
<script type="text/javascript" src="static/mp\_load.js"\></script\>
1.3、修改API文件加载瓦片路径
在 baidu-api.js 文件中,可以用 getTilesUrl 多找几次,定位到下面代码:
Hd.getTilesUrl = function(a, b, c) { var e = a.x, a = a.y, f = Sb("normal"), g = 1, c = Gd[c]; this.map.Yw() && (g = 2); e = this.map.oh.Uv(e, b).Ol; return (Fd[Math.abs(e + a) % Fd.length] + "?qt=vtile&x=" + (e + "").replace(/-/gi, "M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + g + (6 == z.ga.ma ? "&color_dep=32&colors=50" : "") + "&udt=" + f).replace(/-(\d+)/gi, "M$1") };
修改如下:
Hd.getTilesUrl = function(a, b, c) { var e = a.x, a = a.y, f = Sb("normal"), g = 1, c = Gd[c]; // this.map.Yw() && (g = 2); // e = this.map.oh.Uv(e, b).Ol; // return (Fd[Math.abs(e + a) % Fd.length] + "?qt=vtile&x=" + (e + "").replace(/-/gi, "M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + g + (6 == z.ga.ma ? "&color_dep=32&colors=50" : "") + "&udt=" + f).replace(/-(\d+)/gi, "M$1") //////加载本地瓦片 let tdir = bmapcfg.tiles_dir.length>0?bmapcfg.tiles_dir:bmapcfg.home + "tiles"; console.log(tdir + "/" + b + "/" + e + "/" + a + bmapcfg.imgext); return tdir + "/" + b + "/" + e + "/" + a + bmapcfg.imgext; // 使用本地的瓦片 ////// };
在这里可将调用瓦片的地址打印出来看看是否正确:
如果瓦片存在,且路径正确,就能正常显示地图了。
ps:地图不能显示出来,是瓦片相关有问题
地图的功能不能实现,是模块相关有问题
这里在 mp_load.js 里已经取到了主路径,可以将之前加载模块处代码修改成:
1.4、关于地图下载器
太乐
太乐地图下载器在没有付费的情况下,最高只能下载12级,而且文件数量有限制,也就是说如果你选择的区域很大,可能连12级都无法下载,比如这里,我要下载中国地图,只能下载到第8级:
而且下载下来的瓦片会有很大很夸张的水印:
但是,如果你买了vip,那就没有任何限制了,具体收费情况我没问
水经注
我没用水经注来说明,是因为水经注下载器,如果没有付费,下载不了瓦片。水经注的购买费用大概800元,买了后没有限制,一直可用。
瓦片文件大小
这是中国地图瓦片,可以看到第11级就1G了,16级1T,17级4T。如果你的地图需要带缩放功能,就吧这些大小累加,几T吧~~
来感受下11级的缩放程度,根本不够用
15级的凑合:
17级:
——————————————–特别注意——————————————
作为一个技术猿,怎会花钱去买,所以经过不懈努力,找到了可以下载完整瓦片的地图下载器,作为题主,自然要拿出来分享,通过以下内容,到百度云下载即可:
https://pan.baidu.com/s/1Mxvf…
提取码:
ojji
如果可以帮助到你,麻烦小手点个赞,走一波爱心支持,小生在此谢过
2、通过Nginx反向代理在项目中引用瓦片
原文地址:https://segmentfault.com/a/1190000021538475
相关推荐
-
ES6 函数的扩展 javascript/jquery
2019-10-9
-
Promise从两眼发懵到双眼放光(3)-Promise的几个关键问题(一) javascript/jquery
2020-5-28
-
在实战中学typescript – 实现浏览器全屏(100行) javascript/jquery
2020-5-20
-
高级 Vue 技巧:控制父类的 slot javascript/jquery
2020-5-26
-
套公式让你不再害怕JavaScript中的原型链 javascript/jquery
2019-3-9
-
你可能不是那么了解的 CSS Background javascript/jquery
2020-6-11
-
技术流:纯代码模拟登录耐克官网思路分享 javascript/jquery
2020-5-26
-
【永久开源】layuimini,最简洁、清爽、易用的layui后台框架模板。保证一用就会爱上它。 javascript/jquery
2019-6-22
-
button与input[type=”button”]的区别 javascript/jquery
2019-5-11
-
threejs海面模拟 javascript/jquery
2020-5-20