最近在做一个国网的一个项目,需要实现一些散点图的标注等;而且需要在内网使用,感觉使用 echarts 就可以简单的实现无需加载类似 openlayers ,leaflet 等 webgis 框架然后再发布地图服务实现。
实现思路 :
- 百度地图API文件
- 创建本地工具资源文件getModules.js
- 地图瓦片
百度地图API文件
首先需要准备离线的百度地图 API 文件,浏览器打开地址:http://api.map.baidu.com/api?v=2.0,不需要申请 key,当然申请也是可以的;打开之后如下:
(function(){ window.BMap_loadScriptTime = (new Date).getTime(); document.write('<script type="text/javascript" src="http://api.map.baidu.com/getscript?v=2.0&ak=&services=&t=20230104104957"></script>');})();
复制 script 加载的 src 地址,在浏览器中打开;如下:

然后复制里面的内容,保存到自己的项目中命名为:baiduApi.js;这个名字随意起;
可以将复制的百度地图API的代码在 https://www.bejson.com/jshtml_format/这里进行格式化;这样看的比较清楚。
修改API文件

function pa(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)}
创建本地工具资源文件getModules.js
继续在我们保存的百度地图API中搜索 domain.main_domain_cdn.baidu[0],找到使用它的地方,修改为’';

if (!this.map.Wb() && (a ? this.map.B.l0 = a: a = this.map.B.l0, a)) for (var c = p,c = "2" == B.xz ? [''] : ['', B.url.proto + B.url.domain.main_domain_cdn.baidu[1] + "/", B.url.proto + B.url.domain.main_domain_cdn.baidu[2] + "/"], d = 0, e; e = this.an[d]; d++) if (e.OO == o)
加载模块短路处理
首先创建一个我们本地工具模块保存的脚本,本项目中命名为getModules.js;
然后在我们保存的百度地图API中搜索搜索 &mod=,替换。那个 console.log(a),是为了给后面创建getModules.js,用于打印出需要加载的工具模块;注意这里的函数 pa,就是我们前面去掉ak验证:添加 if (/^http/.test(a)) return;的方法。

load: function(a, b, c) {var d = this.jb(a);if (d.Dd == this.Mj.Aq) c && b();else {if (d.Dd == this.Mj.XG) {this.TK(a);this.iO(a);var e = this;e.gD == q && (e.gD = o, setTimeout(function() {for (var a = [], b = 0, c = e.Sd.Xn.length; b < c; b++) {var d = e.Sd.Xn[b],l = "";ka.qz.NK(d) ? l = ka.qz.get(d) : (l = "", a.push(d + "_" + Jc[d]));e.Sd.uw.push({zN: d,qF: l})}e.gD = q;e.Sd.Xn.length = 0;// 0 == a.length ? e.EL() : sa(e.QG.OQ + "&mod=" + a.join(","))0 == a.length ? e.EL() : sa('/static/plugins/getModules.js')console.log(a, '1231地图')},1));d.Dd = this.Mj.xQ}d.ov.push(b)}},
创建本地工具资源文件getModules.js
在这里面放API需要调用的模块,上面打印的数组a里面是需要请求的模块,打印出来,通过下面方式获取,放到getmodules.js,例如 canvablepath_lf42rt2, 通过http://api0.map.bdimg.com/getmodules?v=2.0&t=20230207&mod=canvablepath_lf42rt2下载。
复制内容保存到getmodules.js文件中,注意:将我们上一步骤打印的a中所有的内容都需要按照这种方法保存到getmodules.js文件中;
下载地图瓦片
获取瓦片请求地址
在保存的百度地图API脚本中搜索getTilesUrl方法:

Zd.getTilesUrl = function(a, b, c) {var d = a.x,a = a.y,e = Wb("normal"),f = 1,c = Yd[c];this.map.jy() && (f = 2);d = this.map.fb.Ds(d, b).tm;var nURL = (Xd[Math.abs(d + a) % Xd.length] + "?qt=vtile&x=" + (d + "").replace(/-/gi, "M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + f + (6 == x.da.ma ? "&color_dep=32&colors=50": "") + "&udt=" + e + "&from=jsapi2_0").replace(/-(\d+)/gi, "M$1")window.xxxUrls = window.xxxUrls || [];var nname = 'tiles' + '/' + b + '/' + d + '/' + a + '.png'var urlArr = {url: nURL,name: nname}window.xxxUrls.push(urlArr)console.log(nname,nURL,'123456')return nURL}
我们将每个瓦片请求的地址存放到了window.xxxUrls 数组中;在浏览器中打印该数组。
先对地图进行拖拽,确保想要的省市都出现在窗口可视范围内,然后会将每个瓦片请求的地址保存到window.xxxUrls 数组中;不过需要放大到每个级别然后进行拖拽显示完成整个需要下载的范围。这样保证将指定级别获取所有范围图片的地址。
下载瓦片
首先获取到window.xxxUrls 数组中的数据,可以在前端发送 ajax请求,然后进行下载。只做了简单的下载,直接在浏览器中打印window.xxxUrls 数组,然后复制内容,到下面down.js文件:
const imgArr = [{"url":"http://maponline3.bdimg.com/tile/?qt=vtile&x=6327&y=2356&z=15&styles=pl&scaler=1&udt=20200514&from=jsapi2_0","name":"tiles/15/6327/2356.png"}]
const newArr = new Set(imgArr); //去重
const finalArr = Array.from(newArr);
//创建目录
const fs = require('fs');
// const axios = require('axios');const request = require('request');
const path = require('path')const hostdir = "./";
function mkdirSync(dirname) {if (fs.existsSync(dirname)) {return true;} else {if (mkdirSync(path.dirname(dirname))) { fs.mkdirSync(dirname);return true;}}return false
}
var n = 0;
for (const item of finalArr) {const last = item.name.lastIndexOf('/')if (last > 0) {const name = item.name.substr(last + 1)const dir = item.name.substr(0, last)const dstpath = hostdir + dir + '/' + nameif (name.length && dir.length && !fs.existsSync(dstpath)) {if (mkdirSync(hostdir + dir)) {++ n;request(item.url).pipe(fs.createWriteStream(dstpath))}}}
}
然后运行命令 node down.js,执行完之后就会看到下载的tiles文件夹.
也可以使用第三方工具下载瓦片。推荐使用 Bigemap GIS Office
使用离线瓦片进行加载
还是找到我们刚刚修改的getTilesUrl的位置,修改如下:
注意加载的tiles文件夹的地址要写正确。
Zd.getTilesUrl = function(a, b, c) {var x=a.x,y=a.y,e=1,z=a// return '/static/plugins/tiles/'+b+"/"+x+'/'+y+'.png'return '/static/plugins/tiles/'+b+"/"+x+'/'+y+'.png'};
其他:使用离线api和地图时,发现地图出现空白的正方形图块。

修改离线api 的另一个getTilesUrl 方法。

e.getTilesUrl = function(b, d) {// var e = b.x,// e = this.map.fb.Ds(e, d).tm,// j = b.y,// l = Wb("normal"),// m = 1;// this.map.jy() && (m = 2);// l = "customimage/tile?qt=customimage&x=" + e + "&y=" + j + "&z=" + d + "&udt=" + l + "&scale=" + m + "&ak=" + ra;// l = a.styleStr ? l + ("&styles=" + encodeURIComponent(a.styleStr)) : l + ("&customid=" + a.style);// l = c[Math.abs(e + j) % c.length] + l;// return l = Gc(l)// 下面是修改的代码,上面是旧代码var x=b.x,y=b.y,m=1,l = Wb("normal")// return '/static/plugins/tiles/'+b+"/"+x+'/'+y+'.png'return '/static/plugins/tiles/'+d+"/"+x+'/'+y+'.png'};
这样就完成了百度地图的离线加载。
echart 中加载百度地图
首先项目中使用我们下载的百度地图api文件,有两种方式,一种是在public文件夹下的index.html中直接使用、
<script src="./static/plugins/echarts-4.8.0/echarts.min.js"></script><script src="./static/plugins/baiduApi.js"></script>
另一种是直接在项目的入口文件引入。
import '../static/plugins/baiduapi.js'
FAQ
echarts示列
百度地图3.0离线地图教程和echarts的结合使用
参考













