简介:一份面向需要在无网络或弱网环境下使用百度地图的开发者与用户的离线地图源码包,重点解决瓦片下载、本地存储和地图服务搭建等问题。压缩包共6个文件,总大小约23.94MB,涵盖txt说明文档、war包、zip源码包及properties配置文件,便于对照学习部署流程与参数设置。已有112人浏览学习。内容基于实际可运行的离线地图下载工具,包含瓦片抓取、本地HTTP服务配置等核心代码,并附有环境配置与使用说明。通过学习可掌握百度地图瓦片按层级下载、KML/XML元数据配置以及本地地图服务启停等关键操作,适用于户外探险、车辆导航、内部系统离线GIS展示等场景。建议使用者留意离线数据时效与版权协议,并结合自身需求调整下载区域和缩放级别。
1. 百度离线地图源码下载与部署:先弄清它解决什么问题
如果你在内网或者隔离网环境里做过地图需求,大概率会被同一件事卡住:页面画好了,但地图瓦片全是从公网拉的,网络一断,地图就只剩一个灰底。另一种情况是会议演示、应急演练、园区安防这类场景,地图必须稳定,不能依赖对方网络质量。所谓百度离线地图源码下载与部署,指的就是一套把百度地图的瓦片数据下载到本地,再用前端源码渲染这些瓦片,最终跑在自己的服务器上的完整方案。它能解决的不是“能不能显示地图”这么简单,而是让地图底图、缩放、标记、图层完全脱离公网,在地理信息又被监管的行业里,做到真正可控。
这套方案适合谁?前端工程师想把地图模块做成离线包,运维同学需要在内网提供稳定底图服务,以及做 GIS 项目但不想把底图依赖交给第三方在线服务的技术人员。整个过程拆开看就四件事:搞懂百度瓦片规则、下载靠谱的源码、配置正确参数、躲开常见坑。下文直接按这条路走。
2. 下载前先吃透百度瓦片规则:坐标系、瓦片编号与三种源码形态
离线地图不是把在线地图的网页保存下来就能用,核心在于你拿到的那套源码,是不是基于百度地图的瓦片编号规则去渲染。很多人下载了一堆源码,部署起来就是黑屏,多半是因为这里没对齐。
2.1 百度地图为什么用自己的一套瓦片编号,和普通瓦片差在哪
百度地图的底图采用 BD-09 坐标系,这是在国家通用坐标基础上又做了一层二次加密。它的瓦片编号也因此自成体系,x、y、z 三个参数和常见的 WGS-84 瓦片规则并不相同。普通切片地图(如 OSM、高德)大多数遵循 XYZ 标准:原点在左上角,y 轴向下递增。百度为了配合自身的墨卡托投影和加密偏移,瓦片切分在高层级上会有明显位移,而且瓦片地址里有个qt=tile之类的参数标志。
我见过有人把 OSM 的离线瓦片直接改个文件夹名想套进百度地图页面,结果地图不显示。原因就在坐标系和编号源头不一致。你能下载到的“百度离线地图源码”,本质上都内置了一套从 BD-09 经纬度换算成瓦片行列号的算法,或者一段自定义的getTileUrl函数。源码是否可靠,第一件事就是看它有没有处理百度瓦片编号的转换逻辑,而不是直接用 Leaflet 默认的瓦片规则。
2.2 三种常见的“离线地图源码”形态,怎么选才不后悔
在社区里搜“百度离线地图源码”,你大概率会看到三类仓库,形态不同,部署难度完全不同。
第一类是纯前端离线源码。它包含一个地图页面、百度瓦片渲染脚本和一个空的tiles目录,瓦片数据要自己去下载。优点是代码干净,容易改主题色和交互;缺点是你得先解决瓦片从哪来。这种适合单城市、单楼层或园区级别的小范围地图。
第二类是带瓦片下载器的源码。页面之外多了一个工具,可以输入经纬度范围、最小和最大缩放级别,自动从百度瓦片服务拉取图片到本地。这类源码对新手最友好,因为数据获取和渲染是用同一套瓦片编号算法写好的,不容易出现坐标错位。缺点是下载瓦片比较耗时,代码仓库通常比较大。
第三类是“一体化离线地图包”,常见形态是把全国几个缩放级别的瓦片打包放进源码里,解压即可运行。这种方案适合需要多城市调用的场景,但体积可能几百 GB,服务器磁盘和网络传输都是门槛。选型时别贪大,先想清楚你的业务范围半径。
2.3 我判断一套源码能不能用的三个硬指标
下载源码之前,先看三件事,能省掉后面一整天的排错时间。
第一,源码里是否允许自定义瓦片路径。线上版可能写死域名,比如maponline0.bdimg.com,离线版必须支持把路径改成相对目录./tiles/{z}/{x}/{y}.png。如果源码里瓦片 URL 写死成 http 开头,且没有全局配置项,那它根本不是离线版,只是把在线接口换了个壳。
第二,是否自带跨域方案。瓦片文件从本地服务器加载属于同源,一般没问题,但如果用 File 协议直接双击打开页面,浏览器会拦截本地文件请求,这个坑我后面的排错章节会专门讲。源码如果给出了 nginx 配置示例,说明作者考虑过部署环节,可靠性更高。
第三,瓦片下载工具和渲染脚本是否绑定同一套坐标系逻辑。有些下载器抓下来的瓦片是原始百度编号,但前端页面却用 Leaflet 的标准 XYZ 去读,结果地图整体偏移几个像素到几个街区。选源码时,最好把下载器和渲染页面来自同一个仓库,或者参数接口完全一致。下面这张表可以帮你快速判断:
| 维度 | 纯前端源码 | 带下载器源码 | 一体化离线包 |
|---|---|---|---|
| 瓦片来源 | 需自行解决 | 工具自动拉取 | 已内置 |
| 部署难度 | 中 | 低 | 极低 |
| 磁盘占用 | 取决于瓦片范围 | 可控 | 通常很大 |
| 适合场景 | 二次开发 | 新手快速落地 | 全量离线运营 |
3. 在本地把源码跑起来:最小目录结构与两条启动命令
拿到源码后,第一件事不是读代码,而是先让它能跑。越早看到地图页面,你越有信心继续往下改。下面这个流程是拿任意一套常规离线地图源码做的演示,你在自己的项目里可以照搬。
3.1 先看清目录结构:一份能跑的离线地图源码长什么样
一份合格的离线地图源码,不管前端框架是什么,核心目录结构大同小异。下面的文件树是我习惯的组织方式:
offline-map/ ├── index.html ├── config.js ├── lib/ │ ├── leaflet.js │ └── bdmap-convert.js ├── tiles/ │ └── z7/ │ ├── x3/ │ │ ├── y5.png │ │ └── y6.png │ └── x4/ │ └── y5.png └── README.md用tree -L 3 offline-map就能看到类似结构。重点看lib/bdmap-convert.js这个文件,它负责把百度墨卡托坐标转换为瓦片行列号。没有它,瓦片路径永远对不上。config.js是全局配置入口,后续改中心点、缩放级别都在这里。
提示:有些源码把瓦片放在static/tiles或assets/map/tiles下,这不影响原理,但部署时要保持一致。
3.2 本地起服务:python3 http.server 与 nginx 两条路
很多人第一次跑离线地图,直接双击index.html,结果地图空白。别踩这个坑,地图瓦片是通过 HTTP 请求加载的,File 协议默认不能跨文件读取。本地调试最省事的方式是 Python 自带的服务,你机器上有 Python 3 的话,直接执行:
cd offline-map python3 -m http.server 8080然后访问http://localhost:8080/index.html。这个命令会把当前目录作为网站根目录,瓦片路径只要写成相对路径,浏览器就会按目录结构去tiles下找图片。如果你更习惯 nginx,经典配置如下:
server { listen 80; server_name localhost; root /data/offline-map; index index.html; location /tiles/ { # 瓦片文件较大,关掉访问日志,减少 IO 开销 access_log off; } }两种方式都行。我一般本地用 Python,部署到服务器用 nginx。Python 服务简单,但生产环境性能和并发都不如 nginx;nginx 配置 rtmp 之外的静态资源服务很成熟,日志关闭后瓦片响应速度会好很多。
3.3 从网络面板确认瓦片真的从本地加载
页面能打开不代表就是离线了,必须做一个技术验证:打开浏览器开发者工具,切到 Network 面板,刷新页面,然后在过滤框里输入tiles或者.png。
正常的现象是,所有瓦片请求的 URL 都以你的服务器地址开头,比如http://localhost:8080/tiles/z7/x3/y5.png,响应状态码 200。如果 URL 还是以bdimg.com结尾,说明你跑的页面还在请求在线瓦片,也就是源码的瓦片路径没有切换成功。这时候要回config.js里看tileUrlTemplate或者类似命名的配置项,把它改成当前离线环境下的路径模板:
// config.js const mapConfig = { center: [39.9042, 116.4074], // 初始中心点,常见写法是 [纬度, 经度] zoom: 12, // 初始缩放级别 maxZoom: 18, // 最大缩放级别,超出会没有瓦片 tileUrlTemplate: './tiles/{z}/{x}/{y}.png' // 相对路径最保险 };改完刷新,再看 Network,确认请求全走本地,这一步就算跑通了。
4. 部署的核心配置:中心点、缩放级别、瓦片目录与内网路径
地图能显示后,真正的工作才刚开始。离线地图不像在线地图那样“随便放大都能加载出来”,你预先下载了哪些瓦片,页面就只能显示到那个范围。配置不到位,地图会翻车。
4.1 配置文件里最该动的三个字段
我每次部署,最先动的就是config.js里的这三个值:center、zoom、maxZoom。它们决定了用户打开页面第一眼看到什么,以及能放大到什么程度。
// 某园区平面和周边 3 公里底图 const mapConfig = { center: [31.2304, 121.4737], // 园区中心点 zoom: 16, // 默认先看园区 minZoom: 12, // 限制最小缩放,避免拉到没有瓦片的级别 maxZoom: 18, // 对应下载瓦片时的最大级别 tileUrlTemplate: '/offline-map/tiles/{z}/{x}/{y}.png' };这里有一个很容易忽略的点:minZoom。在线地图可以无限缩小到世界地图,但离线地图你大概率只下载了几个城市或一个园区,缩得太小会看到一片空白底。设置minZoom可以让浏览器在地图范围超过已下载瓦片区域时,停止请求新的瓦片,或者只显示灰色背景。建议minZoom设置为下载瓦片时的最小级别,而不是默认值 0。
另一个是tileUrlTemplate中的三级变量{z}/{x}/{y}。这里的 z 是缩放级别,x 和 y 必须和下载器里输出的瓦片目录层级完全一致。比如下载器把第 16 级的瓦片放在tiles/16/xxx/yyy.png,那这里的模板就写成tiles/{z}/{x}/{y}.png,不能自己加一层目录,否则全盘匹配不上。
4.2 瓦片目录层级和缩放级别对不上,地图会怎么崩
这个坑我见过太多次,现象是:地图能移动,但只有某个缩放级别有图,放大或缩小一格后整个地图变成网格纹或灰色。原因是下载瓦片时用户勾选的是某一层,但页面的maxZoom高于下载层级。
举一个实际例子:下载器设置抓取级别 10 到 15,但config.js里maxZoom写的是 18。用户放大到 16 级时,程序按规则请求tiles/16/x/y.png,本地没有这个文件,服务返回 404,地图就会空白。解决办法有两个:一是把maxZoom和minZoom手动调整为下载范围,二是做一个兜底逻辑:让页面在 404 时向上兼容读取上一级的瓦片并放大显示。兜底逻辑虽然能让地图不空白,但会模糊,生产环境不建议依赖它。
正确做法是下载瓦片之前就规划好范围:如果需要展示的只是一个园区,下载 15 到 18 级就够;如果要看城市全貌,至少下载 10 到 18 级。每一级瓦片数量是上一级的 4 倍,级别越高成倍数增长,最好先用小范围测试级别,算清磁盘占用再动手。
4.3 内网服务器部署:根路径和跨域的两个坑
本地跑通后扔到服务器,最常见的问题是样式和瓦片路径全部失效,控制台显示一堆 404。多数情况是“根路径”问题:你的 nginx 把站点部署在/data/www/myapp/,访问域名是http://192.168.1.10/myapp/,而源码里瓦片路径写的是/tiles/...。这个以/开头的绝对路径,会直接跑到服务器的根目录去请求。
解决办法是统一用相对路径,或者按项目路径调整 nginx root。我习惯的项目做法是保持源码里的资源路径全部相对化:
tileUrlTemplate: './tiles/{z}/{x}/{y}.png'然后把整个源码目录直接作为 nginx 的 root 根目录。这样无论你在子路径还是根路径,都不会因为路径前缀丢资源。如果你一定要放在子路径,那 nginx 配置要改成这样:
location /myapp/ { alias /data/offline-map/; index index.html; }注意alias和root的区别,用alias时路径会按/myapp/原样映射到/data/offline-map/下,瓦片请求/myapp/tiles/...能找到文件。用root则会拼接成/data/offline-map/myapp/tiles/...,必然 404。
跨域问题更多出现在瓦片是通过另一个独立服务提供时。比如地图页面在http://10.0.0.2:8080,瓦片静态服务在http://10.0.0.3:8081,浏览器会拦截跨域瓦片请求。最省事的方案是让 nginx 把两个地址合成一个域名,在 nginx 配置里增加转发规则,避免在前端做跨域处理。
4.4 提前算清瓦片磁盘占用,别等服务器磁盘被写满
配置地图范围时,大多数人会低估瓦片总量。一张 256×256 的 PNG 瓦片,在卫星图上可能 100KB 起步,在街道矢量图上也有 20KB 左右。同一级的瓦片数量,如果范围是 10 公里乘 10 公里,16 级以上往往有几万张,磁盘占用会迅速飙升。
下载之前我一般会先算一下:横向范围除以该级瓦片分辨率,得到覆盖的瓦片列数,纵向同理。但这套计算在下载器源码里通常已经实现了,你只需要看下载器启动前的预估提示。它如果显示“约 98500 张瓦片,预计占用 2.1GB”,而你的服务器磁盘只剩 1.5GB,就先缩小范围或者降低最大级别。硬着头皮下载到磁盘满,进程会被中断,瓦片缺失到一半,页面显示不完整,排查起来反而更费劲。
5. 离线地图部署排错避坑:五个常见翻车现场与解决办法
部署离线地图,80% 的时间花在排错上。下面这五个问题是我反复踩过的,按现象到原因到解决步骤写清楚,你遇到直接对照。
5.1 症状一:底图白屏,但控制台没有报错
现象:页面打开后一片空白,Network 面板里没有瓦片请求,控制台也没有 JS 报错,像什么都没发生。
原因:绝大多数情况下是config.js根本没被加载,或者加载顺序错了。比如index.html里把对config.js的引用放在地图初始化解引之后,代码运行时取到mapConfig是undefined,初始化函数直接返回空白。
解决:打开渲染后页面的 Sources 面板,找到config.js文件,确认内容已加载。再看index.html的script加载顺序,正确做法是先加载config.js,再加载地图主程序:
<script src="./config.js"></script> <script src="./lib/leaflet.js"></script> <script src="./lib/bdmap-convert.js"></script>5.2 症状二:瓦片加载出来是歪的,位置整体偏移
现象:地图底图能显示,但标注点和瓦片的地理位置对不上,整体向东或者向南偏移几格,缩放越大偏移量越大。
原因:这是经典的坐标系错位。页面用 BD-09 坐标初始化中心点,但瓦片下载器用的是标准 XYZ 切片规则,或者反过来。百度瓦片必须配套 BD-09 的墨卡托转换函数,偏移现象一出现,先怀疑lib里有没有做坐标转换的模块。
解决:在页面里把百度坐标转成瓦片坐标的过程打印出来,对照百度地图在线版同一个经纬度,在相同缩放级别下应该落在同一块瓦片上。如果打印出来的 x/y 行列号对不上,就去换源码里那段转换函数。偷懒的办法是用百度地图官方 JS API 的低级别接口作为基础,包一层离线缓存,但这需要你本地有完整 API 文件,源码体积会大很多。
5.3 症状三:本地双击能开,部署到服务器后显示不了
现象:index.html在电脑上双击可以用浏览器打开并看到地图,但放到 nginx 服务器后,访问 URL 反而白屏或丢样式。
原因:双击打开是 File 协议,浏览器允许页面访问同目录下的相对资源,但好多浏览器环境下 File 协议对某些类型的异步请求有限制,尤其当一个页面通过/tiles/...这样的绝对路径请求资源时,File 协议下/会被解析成磁盘根目录,自然找不到。本地能用,是因为源码里写的是相对路径;部署到服务器后如果被改成绝对路径,或者服务器配置了子路径,就会失败。
解决:统一使用./开头的相对路径,并测试这两种场景:直接以站点根路径访问,和以/myapp/子路径访问。要做到两种都能显示,最稳妥的是在index.html里用<base href="./">声明基准路径,让所有相对请求都从当前页面目录开始解析。
5.4 症状四:瓦片请求失败,提示 CORS 跨域错误
现象:Network 面板能看到瓦片请求,但响应是红色的,控制台提示CORS policy相关的错误,瓦片加载不进来。
原因:地图页面和瓦片文件不在同一个域,浏览器默认拦截跨域加载的图片。常见场景是页面在 80 端口,瓦片服务在 8081 端口,后端没有返回Access-Control-Allow-Origin响应头。
解决:如果你能用 nginx 统一入口,就不要走跨域。把瓦片目录放在同域名下,用 nginx 的location配置将瓦片请求指向本地目录。如果瓦片必须存在另一台服务器,在那台服务器的 nginx 里加一行头:
add_header Access-Control-Allow-Origin *;生产环境不建议用*通配符,改成实际的地图域名更安全。不过离线地图通常跑在内网,跨域本身就是低频需求,优先选同域方案。
5.5 症状五:瓦片下载到一半停止,页面缺块严重
现象:下载瓦片时进度条卡住,或者提示磁盘空间不足,再看地图某些区域没有瓦片,放大后缺块。
原因:下载器在脚本中断后不会自动检测哪些瓦片缺失,再启动时往往从头重来或跳过已存在文件。更常见的是磁盘占满导致文件写了一半,PNG 文件不完整,浏览器能拿到请求但图片无法解码。
解决:下载器尽量选择支持断点续传和存在校验的工具。没有的话,下载完做一次完整性检查:
# 找出所有体积为 0 或者小于 1KB 的瓦片文件 find tiles/ -type f -size -1k -exec ls -lh {} \;把不完整的文件删掉后重新下载。下载过程中留意df -h,一般我要求磁盘剩余空间至少是预估瓦片体积的 1.5 倍,给临时文件和后续追加预留余地。
6. 把离线地图接进业务:数据叠加、断网验证与维护小习惯
离线地图部署完成,只是底图到位。业务真正需要的是地图上的点位、区域和路线,这部分需要你在离线源码基础上叠加自己的数据图层。
6.1 叠加业务数据:给页面加一个 GeoJSON 图层
如果你选的是 Leaflet 作为渲染引擎,叠加数据非常方便。假设你有一份设备点位文件devices.geojson,把它放在源码data目录下,地图初始化后加载:
fetch('./data/devices.geojson') .then(res => res.json()) .then(data => { L.geoJSON(data, { pointToLayer: (feature, latlng) => { return L.marker(latlng, { icon: deviceIcon }); } }).addTo(map); });这段代码把 geojson 里的每个点变成一个标记。注意latlng的纬度经度顺序要和百度坐标一致,否则点位会偏到海里。如果你从在线百度地图导出的数据是加密坐标,而叠加的 geojson 是标准 GPS 坐标,那就需要先在转换函数里做 BD-09 到 WGS-84 的逆处理,这是个典型细节,别直接照着 API 写。
6.2 断网验收:离线地图到底能不能“绝对离线”
做完数据叠加,必须做一次断网测试。拔掉服务器网线,或者在没有外网连接的虚机里访问地图,确认底图、瓦片、业务数据、图标全部从本地加载。这一步能暴露很多潜在问题,比如 index.html 里是否引入了某个公网 CDN 的 JS 库,或者瓦片请求是否有一小部分还在走在线地址。
我常用的验证命令是:
# 先看有没有外链 grep -rE "http://|https://" index.html lib/ | grep -v "localhost\|127.0.0."有输出就说明还有外链依赖。全部清掉后,断网刷新页面,地图必须依然能缩放、能拖拽、能显示点位。这一步过了,离线状态才算真正成立。
6.3 维护小习惯:瓦片更新要留版本号
离线地图不是部署完就结束。底图需要更新时,如果直接覆盖tiles目录,老瓦片和新瓦片混在一起,用户会看到新旧风格不一,甚至因为坐标算法调整导致位置偏移。我现在的做法是给瓦片目录带版本号,比如tiles_v2/,更新时切换配置文件里的路径前缀,保留旧版本便于快速回滚。这个小习惯不复杂,但能在关键时候救命。
说到底,百度离线地图源码下载与部署并不神秘,本质上就是把在线瓦片换成离线文件,把动态接口换成静态服务。难点不在代码,而在坐标系是否统一、路径是否相对化、瓦片范围是否和服务能力匹配。你按这个流程走,把配置调对、坑避开,内网地图的稳定性会远好过在线方案。这也是我做过几个项目后最深的感受:离线地图不怕慢,怕乱,目录和路径从一开始就理理清,后面能省下无数个加班的夜。希望帮到你。
本文还有配套的精品资源,点击获取