web百度离线地图开发(详细教程)2019

web百度离线地图开发(详细教程)

  • 需求情景
  • 主要参考
  • 开发步骤
    • 一、JS API文件下载
    • 二、修改API文件
      • 1、屏蔽ak验证
      • 2、设置引用本地资源路径
      • 3、下载本地资源
      • 4、引用本地资源
    • 三、加载瓦片改为本地离线瓦片
      • 1、存储目录
      • 2、下载瓦片
      • 3、瓦片配置文件
      • 4、修改加载瓦片路径
    • 四、关于离线
    • 五、关于地图下载器
      • 1、免费/付费
      • 2、瓦片文件的大小

需求情景

项目在内网上使用,不得连接外网,所以需要开发离线地图功能
这个项目是vue+vue-cli的,需要对vue和这种项目结构有些了解
这是自己写的vue项目构建的文章,很详细,不了解的可以看看:
https://blog.csdn.net/PGguoqi/article/details/88977403

主要参考

我这里算是对这次开发做个总结,主要参考了下面两篇文章,但是因为或多或少都不是很详细,中间卡了好久,最后捣鼓出来了,所以写个文章记录分享下,照着一步一步走,绝对能开发出来。
https://blog.csdn.net/wml00000/article/details/82219015
https://blog.csdn.net/a312024054/article/details/70213444
如有谬误,还望指正。希望对大家有所帮助

开发步骤

一、JS API文件下载

访问这个地址 http://api.map.baidu.com/api?v=3.0 ,打开之后是一段代码:
这个是引入在线js文件时的地址在代码中找到 src="http://api.map.baidu.com/getscript?v=3.0&ak=&services=&t=20180823175819",打开这个链接,就可以看到压缩后的js代码,这个是我们要用到的代码:
web百度离线地图开发(详细教程)2019_第1张图片
在站长工具 http://tool.chinaz.com/tools/jsformat.aspx 将上面的压缩代码格式化备用,以便下面查看与修改。
static/js目录下新建个js文件,我这里命名为 bmap_offline_api_min.js ,将上面格式化后的js代码复制到这个文件中:
web百度离线地图开发(详细教程)2019_第2张图片
最后,需要在入口index.html的head中引入这个js:
web百度离线地图开发(详细教程)2019_第3张图片

二、修改API文件

1、屏蔽ak验证

bmap_offline_api_min.js 文件中,用 Math.random() 多找几次,定位到下列代码位置:
(以下代码方法名称和一些变量名称可能会有出入,我下载的代码就和网上一些贴子上看到的代码不尽相同)

function oa(a, b) {
    if (b) {
        var c = (1E5 * Math.random()).toFixed(0);
        z._rd["_cbk" + c] = function(a) {
            b && b(a);
            delete z._rd["_cbk" + c]
        };
        a += "&callback=BMap._rd._cbk" + c
    }
    var d = K("script", {
        type: "text/javascript"
    });
    d.charset = "utf-8";
    d.src = a;
    d.addEventListener ? d.addEventListener("load",
        function(a) {
            a = a.target;
            a.parentNode.removeChild(a)
        },
        q) : d.attachEvent && d.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(d);
            d = p
        },
        1)
};

然后修改上面的代码,对http拦截,不进行外部访问,只需在最开始加一行代码if (/^http/.test(a)) return;

function oa(a, b) {
	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    if (/^http/.test(a)) return; // !!!!!这里加判断,如果是调用外部资源就退出去
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    if (b) {
        var c = (1E5 * Math.random()).toFixed(0);
        z._rd["_cbk" + c] = function(a) {
            b && b(a);
            delete z._rd["_cbk" + c]
        };
        a += "&callback=BMap._rd._cbk" + c
    }
    var d = K("script", {
        type: "text/javascript"
    });
    d.charset = "utf-8";
    d.src = a;
    d.addEventListener ? d.addEventListener("load",
        function(a) {
            a = a.target;
            a.parentNode.removeChild(a)
        },
        q) : d.attachEvent && d.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(d);
            d = p
        },
        1)
};

2、设置引用本地资源路径

bmap_offline_api_min.js 文件中,用 url.domain.main_domain_cdn.baidu[0] 多找几次,定位到下面的代码:

z.url = z.Y_[z.Qy];
z.wp = z.url.proto + z.url.domain.baidumap + "/";
z.wc = z.url.proto + ("2" == z.Qy ? z.url.domain.main_domain_nocdn.other: z.url.domain.main_domain_nocdn.baidu) + "/";
z.ma = z.url.proto + ("2" == z.Qy ? z.url.domain.main_domain_cdn.other[0] : z.url.domain.main_domain_cdn.baidu[0]) + "/";
z.cj = z.url.proto + z.url.domain.main_domain_cdn.webmap[0] + "/";
z.rg = function(a, b) {
    var c, d, b = b || "";
    switch (a) {
        case "main_domain_nocdn":
...

然后将 z.cj = z.url.proto + z.url.domain.main_domain_cdn.webmap[0] + "/" 改为 z.cj = ''

z.url = z.Y_[z.Qy];
z.wp = z.url.proto + z.url.domain.baidumap + "/";
z.wc = z.url.proto + ("2" == z.Qy ? z.url.domain.main_domain_nocdn.other: z.url.domain.main_domain_nocdn.baidu) + "/";
z.ma = z.url.proto + ("2" == z.Qy ? z.url.domain.main_domain_cdn.other[0] : z.url.domain.main_domain_cdn.baidu[0]) + "/";
//!!!!!!!!!!!!!!!!!!!!!!!
z.cj = '';
//!!!!!!!!!!!!!!!!!!!!!!!
z.rg = function(a, b) {
    var c, d, b = b || "";
    switch (a) {
        case "main_domain_nocdn":
...

3、下载本地资源

所谓本地资源,就是在使用地图时需要用到的一些模块(module),比如图层类,标记类,控件类。

当你在地图中用到这些模块时,它会自动加载,因此我们需要先把这些模块的js文件下载下来,保存到本地。

这些模块有几十个之多,我们这里并不都存本地,而是用到哪个下载哪个,那么如何知道用到了哪个模块呢?

  • 首先,在 bmap_offline_api_min.js 文件中,用 &mod= 定位到下面的代码,然后加一行代码将用到的模块打印出来:
load: function(a, b, c) {
    var d = this.ib(a);
    if (d.Bd == this.Fj.cq) c && b();
    else {
        if (d.Bd == this.Fj.pG) {
            this.lK(a);
            this.zN(a);
            var e = this;
            e.DC == q && (e.DC = o, setTimeout(function() {
                    for (var a = [], b = 0, c = e.Pd.Fn.length; b < c; b++) {
                        var d = e.Pd.Fn[b],
                            l = "";
                        ia.Ly.fK(d) ? l = ia.Ly.get(d) : (l = "", a.push(d + "_" + Rb[d]));
                        e.Pd.Tv.push({
                            TM: d,
                            KE: l
                        })
                    }
                    e.DC = q;
                    e.Pd.Fn.length = 0;
                    //!!!!!!!!!!!!!!!!!!!!
                    console.log(a);   //!!!!!打印所需模块,这很重要
                    //!!!!!!!!!!!!!!!!!!!!
                    0 == a.length ? e.XK() : oa(e.iG.$P + "&mod=" + a.join(","))
                    0 == a.length ? e.UK() : Qb("js/getmodules2.0.js")
                },
                1));
            d.Bd = this.Fj.JP
        }
        d.Ru.push(b)
    }
},
  • 然后,我们在需要使用地图的vue页面里,按照官方文档正常使用:(具体功能去官网找dome示例即可)
mounted(){
    this.$nextTick(() => {
        // 百度地图
        var map = new BMap.Map("container");
        var point = new BMap.Point(106.550963, 29.572012);
        map.centerAndZoom(point, 12);
        
        //设置定位点的弹跳动画
        var marker = new BMap.Marker(point);  // 创建标注
        map.addOverlay(marker);               // 将标注添加到地图中
        marker.setAnimation(BMAP_ANIMATION_BOUNCE); //跳动的动画
        map.enableScrollWheelZoom(true);
        //添加工具条比例尺控件
        var top_left_control = new BMap.ScaleControl({anchor: BMAP_ANCHOR_TOP_LEFT});// 左上角,添加比例尺
        var top_left_navigation = new BMap.NavigationControl();  //左上角,添加默认缩放平移控件
        var top_right_navigation = new BMap.NavigationControl({anchor: BMAP_ANCHOR_TOP_RIGHT, type: BMAP_NAVIGATION_CONTROL_SMALL}); //右上角,仅包含平移和缩放按钮
        map.addControl(top_left_control);
        map.addControl(top_left_navigation);
        map.addControl(top_right_navigation);
    })
},

特别注意:如果你要在进入页面就初始化地图,最好像上面那样,放在 mounted 生命函数的 this.$nextTick(() => {}) 里,以确保地图容器 #container 元素渲染完成,不然有可能因为初始化时地图容器还未渲染而报错:
在这里插入图片描述
刷新这个vue页,关注控制台,就能看到要实现这些地图功能所需要的模块名,是个数组集合,如下图,我这里需要"control_ff1mc0", "navictrl_wxtn3y"两个模块:
在这里插入图片描述

  • 这样获得模块文件
    这个链接 http://api0.map.bdimg.com/getmodules?v=2.0&t=20140707&mod=infowindow_omcokh,将其中 &mod= 之后的参数替换成我们打印出来的模块名,比如:
    http://api0.map.bdimg.com/getmodules?v=2.0&t=20140707&mod=control_ff1mc0
    http://api0.map.bdimg.com/getmodules?v=2.0&t=20140707&mod=navictrl_wxtn3y
    分别访问上述链接,就可以看到模块文件代码:
    web百度离线地图开发(详细教程)2019_第4张图片
  • 在static文件夹下新建modules文件夹来存放即将下载的模块文件:
    web百度离线地图开发(详细教程)2019_第5张图片
    新建以模块名命名的js文件,将模块文件代码粘贴到响应模块js文件里。这样需要的模块文件就下载好了。有几个模块下载几个文件:
    web百度离线地图开发(详细教程)2019_第6张图片

4、引用本地资源

在上面步骤打印模块名的地方,做如下修改:

load: function(a, b, c) {
    var d = this.ib(a);
    if (d.Bd == this.Fj.cq) c && b();
    else {
        if (d.Bd == this.Fj.pG) {
            this.lK(a);
            this.zN(a);
            var e = this;
            e.DC == q && (e.DC = o, setTimeout(function() {
                    for (var a = [], b = 0, c = e.Pd.Fn.length; b < c; b++) {
                        var d = e.Pd.Fn[b],
                            l = "";
                        ia.Ly.fK(d) ? l = ia.Ly.get(d) : (l = "", a.push(d + "_" + Rb[d]));
                        e.Pd.Tv.push({
                            TM: d,
                            KE: l
                        })
                    }
                    e.DC = q;
                    e.Pd.Fn.length = 0;
                    console.log(a);   //!!!!!!打印所需模块
                    // 0 == a.length ? e.XK() : oa(e.iG.$P + "&mod=" + a.join(","))
                    // 0 == a.length ? e.UK() : Qb("js/getmodules2.0.js")
                    // !!!!!!!!!!!!!!!!!!!!!!!!引用本地下载好的模块文件资源
                    if( a.length > 0 ){
                        for(let i=0; i<a.length;i++){
                            let mf = './static/modules/'+a[i]+'.js';
                            oa( mf );
                            console.log('加载模块文件:'+mf); //IE error
                        }
                    } else {
                        e.XK()
                    }
                     // !!!!!!!!!!!!!!!!!!!!!
                },
                1));
            d.Bd = this.Fj.JP
        }
        d.Ru.push(b)
    }
},

现在就能成功加载模块资源了。
这里要注意路径问题,如果路径不对,找不到模块文件,会报错:
web百度离线地图开发(详细教程)2019_第7张图片

三、加载瓦片改为本地离线瓦片

离线瓦片可以理解为地图离线包,没有它,离线地图是无法显示的。

1、存储目录

首先,在 static 目录下新建文件夹 tiles 来存放瓦片:
web百度离线地图开发(详细教程)2019_第8张图片

2、下载瓦片

用水经注或者太乐地图下载器下载瓦片,我用太乐。

选择百度
web百度离线地图开发(详细教程)2019_第9张图片
下载 -> 选择行政区划,选完了之后该区域就会出现ufo图标
web百度离线地图开发(详细教程)2019_第10张图片
点击图标,选择 地图
web百度离线地图开发(详细教程)2019_第11张图片
选择直接保存瓦片后,存储标准选择百度瓦片,存储格式会自动选择 .png。然后选择级别之后确定即可:web百度离线地图开发(详细教程)2019_第12张图片
级别就是调用百度地图api处设置的缩放级别:
在这里插入图片描述
下载完成后可在这里查看:web百度离线地图开发(详细教程)2019_第13张图片
找到存储目录:我这里下载了重庆12级的瓦片,所有的瓦片就存储在了12这个文件夹下
web百度离线地图开发(详细教程)2019_第14张图片
将12这个文件夹整个复制到项目static/tiles目录下
web百度离线地图开发(详细教程)2019_第15张图片
你会发现除了下载了12级,还下载了9、10、11级,因为离线的关系,在地图上进行缩放操作到11级,但是如果没有11级的瓦片,地图就什么都不显示。所以如果想要缩放多少级,这些级别的瓦片必须都下载到本地。

3、瓦片配置文件

static目录下新建mp_load.js文件,定义瓦片路径及瓦片格式即地图api的主目录:
web百度离线地图开发(详细教程)2019_第16张图片
我们的瓦片是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文件之前引入该配置文件:
web百度离线地图开发(详细教程)2019_第17张图片

4、修改加载瓦片路径

bmap_offline_api_min.js 文件中,可以用 getTilesUrl 多找几次,定位到下面代码:

Yc.getTilesUrl = function(a, b, c) {
    var d = a.x,
        a = a.y,
        e = Qb("normal"),
        f = 1,
        c = Xc[c];
    this.map.Ix() && (f = 2);
    d = this.map.eb.Bw(d, b).ds;
    return (Wc[Math.abs(d + a) % Wc.length] + "?qt=vtile&x=" + (d + "").replace(/-/gi, "M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + f + (6 == x.da.la ? "&color_dep=32&colors=50": "") + "&udt=" + e).replace(/-(\d+)/gi, "M$1")
}

修改如下:

Yc.getTilesUrl = function(a, b, c) {
    var d = a.x,
        a = a.y,
        e = Qb("normal"),
        f = 1,
        c = Xc[c];
    // this.map.Ix() && (f = 2);
    // d = this.map.eb.Bw(d, b).ds;
    // return (Wc[Math.abs(d + a) % Wc.length] + "?qt=vtile&x=" + (d + "").replace(/-/gi, "M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + f + (6 == x.da.la ? "&color_dep=32&colors=50": "") + "&udt=" + e).replace(/-(\d+)/gi, "M$1")

    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    let tdir = bmapcfg.tiles_dir.length>0?bmapcfg.tiles_dir:bmapcfg.home + "tiles";
    console.log(tdir + "/" + b + "/" + d + "/" + a + bmapcfg.imgext)
    return tdir + "/" + b + "/" + d + "/" + a + bmapcfg.imgext; // 使用本地的瓦片
     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
};

在这里可将调用瓦片的地址打印出来看看是否正确:
在这里插入图片描述
web百度离线地图开发(详细教程)2019_第18张图片
如果瓦片存在,且路径正确,就能正常显示地图了。

ps:地图不能显示出来,是瓦片相关有问题
地图的功能不能实现,是模块相关有问题

这里在 mp_load.js 里已经取到了主路径,可以将之前加载模块(三 - 4)处代码修改成:(不修改也可)
web百度离线地图开发(详细教程)2019_第19张图片

四、关于离线

离线并不是指断网,而是指只连内部局域网,表现在你无法访问百度,但是本地跑项目localhost的页面是能展示的。
想调试的话可以将本地的ip改为你知道的内网中一个计算机的ip。

五、关于地图下载器

1、免费/付费

  • 太乐
    太乐地图下载器在没有付费的情况下,最高只能下载12级,而且文件数量有限制,也就是说如果你选择的区域很大,可能连12级都无法下载,比如这里,我要下载中国地图,只能下载到第8级:
    web百度离线地图开发(详细教程)2019_第20张图片
    而且下载下来的瓦片会有很大很夸张的水印:
    web百度离线地图开发(详细教程)2019_第21张图片
    但是,如果你买了vip,那就没有任何限制了,具体收费情况我没问
  • 水经注
    我没用水经注来说明,是因为水经注下载器,如果没有付费,下载不了瓦片。水经注的购买费用大概800元,买了后没有限制,一直可用。

2、瓦片文件的大小

这是中国地图瓦片,可以看到第11级就1G了,16级1T,17级4T。如果你的地图需要带缩放功能,就吧这些大小累加,几T吧~~
web百度离线地图开发(详细教程)2019_第22张图片
来感受下11级的缩放程度,根本不够用
web百度离线地图开发(详细教程)2019_第23张图片
15级的凑合:
web百度离线地图开发(详细教程)2019_第24张图片
17级:
web百度离线地图开发(详细教程)2019_第25张图片

你可能感兴趣的:(完整教程)