不用钱!纯前端打包下载离线瓦片地图

简介: 简直无语,瓦片地图明明是开放的,不用钱的,竟然有网站和程序要收费,本人绝不当冤大头,自己动手丰衣足食!其实也有某些免费下载离线地图的良心程序,但因为下载瓦片的请求太频繁了,搞得打开该地图的时候卡死,被人家服务器记住了!

简直无语,瓦片地图明明是开放的,不用钱的,竟然有网站和程序要收费,本人绝不当冤大头,自己动手丰衣足食!
其实也有某些免费下载离线地图的良心程序,但因为下载瓦片的请求太频繁了,搞得打开该地图的时候卡死,被人家服务器记住了!

1.墨卡托投影

就是将原本在地球(假设是球体)的贴图强行铺平成一张矩形贴图,根据再在经纬度和xy坐标做一个转换

v2-00991c24c72667fccdab88740ad108e4_b.jpg

2.瓦片地图

根据地图的缩放等级,对应不同贴图大小,根据墨卡托投影分割成不同放个块,就是对应的瓦片地图,可以根据一下公式进行转换,算出该坐标在哪块瓦片里面

function lon2tilex(lon, zoom) {
   
   
    return Math.floor(((lon + 180) / 360) * Math.pow(2, zoom));
  }
  function lat2tiley(lat, zoom) {
   
   
    return Math.floor(
      ((1 -
        Math.log(Math.tan((lat * Math.PI) / 180) + 1 / Math.cos((lat * Math.PI) / 180)) / Math.PI) /
        2) *
        Math.pow(2, zoom)
    );
  }

image.png

3.使用到的库

  • jszip用于把瓦片地图写入到压缩包里面,统一下载

  • 地图API自己去官网注册一个key,我这里以高德地图为例,如果是百度,腾讯等地图的瓦片,最好用他们的地图,避免经纬度转换的问题,注意:高德和腾讯都用的火星gcj经纬度,百度自己一套的。

  • 相关离线瓦片地图开放地址参考

https://www.cnblogs.com/feiquan/p/14304660.html
https://blog.csdn.net/qq_19689967/article/details/121221727

4.实现步骤

1.定位,在地图确认范围

      drawRect() {
   
   
        this.clearRect();
        this.mouseTool.rectangle({
   
   
          fillColor: '#1e90ff',
          fillOpacity: 0.2,
          strokeColor: '#1e90ff'
        });
        this.mouseTool.on('draw', e => {
   
   
          this.rect = e.obj;
          this.mouseTool.close(false);
          this.rectangleEditor = new AMap.RectangleEditor(this.map, this.rect);

          this.rectangleEditor.open();
        });
      },

2.根据缩放等级范围计算瓦片数量

//获取某个等级的瓦片数量
getTileCount(zoom) {
   
   
        let b = this.rect.getOptions().bounds;
        let x = lon2tilex(b.northEast.lng, zoom);
        let y = lat2tiley(b.northEast.lat, zoom);

        let x1 = lon2tilex(b.southWest.lng, zoom);
        let y1 = lat2tiley(b.southWest.lat, zoom);

        let startx = Math.min(x, x1),
          endx = Math.max(x, x1);
        let starty = Math.min(y, y1),
          endy = Math.max(y, y1);

        return (endx - startx + 1) * (endy - starty + 1);
      },
      //获取不同缩放等级的数量
       getTileLayer() {
   
   
        let b = this.rect.getOptions().bounds;
        let list = [];
        for (let k in this.zoomMap) {
   
   
          if (this.zoomMap[k]) {
   
   
            let z = parseInt(k);
            let x = lon2tilex(b.northEast.lng, z);
            let y = lat2tiley(b.northEast.lat, z);

            let x1 = lon2tilex(b.southWest.lng, z);
            let y1 = lat2tiley(b.southWest.lat, z);

            let startx = Math.min(x, x1),
              endx = Math.max(x, x1);
            let starty = Math.min(y, y1),
              endy = Math.max(y, y1);

            for (let i = startx; i <= endx; i++) {
   
   
              for (let j = starty; j <= endy; j++) {
   
   
                list.push({
   
    x: i, y: j, z });
              }
            }
          }
        }
        return list;
      },

3.根据选择的缩放等级、文件写入规则、瓦片类型,下载写入zip包

高德地图开放瓦片地图资源

styles:[
        {
   
    label: '普通地图', value: '7' },
        {
   
    label: '卫星地图', value: '6' },
        {
   
    label: '路况地图', value: '8' }
      ]
      `http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=${
     
     this.selectStyle ||
              7}&x=${x}&y=${y}&z=${
     
     z}`

获取高德地图瓦片地图,下载的是256x256的png图片,如果需要不同的文件写入目录请自行更改tiles/${z}/${y}/${x}.png,注意一定要setTimeout间隔点时间再请求下一个,避免请求太频繁,被高德地图限制。

writeBlob(x, y, z) {
   
   
        return new Promise(resolve => {
   
   
          getBlob(
            `http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=${
     
     this.selectStyle ||
              7}&x=${x}&y=${y}&z=${
     
     z}`,
            res => {
   
   
              this.theZip.file(`tiles/${z}/${y}/${
     
     x}.png`, res);
              setTimeout(() => {
   
   
                resolve();
              }, 10);
            }
          );
        });
      },

要先将一个zip包放在public文件夹下,获取到zip包再通过JSZip写入瓦片


download() {
   
   
        let tiles = this.getTileLayer();
        this.$msgbox({
   
   
          title: '是否下载?',
          message: `大概需要${
     
     (tiles.length * 0.1).toFixed(2)}秒`,
          showConfirmButton: true,
          showCancelButton: true
        }).then(() => {
   
   
          this.isShow = false;
          this.isLoading = true;
          this.process = 0;
          //写入事先准备好的瓦片地图zip包
          getBlob('tiles.zip', res => {
   
   
            JSZip.loadAsync(res).then(async zip => {
   
   
              this.theZip = zip;

              for (let i = 0; i < tiles.length; i++) {
   
   
                let item = tiles[i];
                await this.writeBlob(item.x, item.y, item.z);
                this.process = ((i / tiles.length) * 100).toFixed(2);
              }
              //写入相关信息
              this.theZip.file(
                `README.md`,
                `# 文件夹目录\n${this.rule}\n\n# 当前地图瓦片 \n 范围:${this.rectLngLat}\n中心点:${
     
     this.centerLnglat}`
              );
              this.theZip.generateAsync({
   
    type: 'blob' }).then(blob => {
   
   
                saveAs(blob, '离线高德地图瓦片' + new Date().format('yyyyMMddhhmmss') + '.zip');
              });
              this.isLoading = false;
            });
          });
        });
      },

完整代码地址

https://github.com/xiaolidan00/offline-map-download

5.使用瓦片地图

画个范围

搜狗截图20230421212506.png

再选择下载缩放等级,然后等待下载的zip包就好

搜狗截图20230421212924.png

zip包目录:README.md就是下载时的相关信息

README.md
# 文件夹目录

tiles/[z]/[y]/[x].png

# 当前地图瓦片 

 范围:113.353114,23.02803;113.43286,23.074142
中心点:113.392987,23.051086

对应瓦片的地址,把zip包的tiles解压放在一个访问的地址

tiles/z/y/x/1234.png

使用离线高德地图maps.js验证下载的瓦片地图

mapBox,mapTalks,Leaflet等常用离线地图验证都行,但是他们都一个通病,就是加载瓦片地图的时候巨卡,而且会出现莫名其妙缺一块的情况(就是你打开文件夹有图片,它就是叛逆不加载的情况)。然后我选择了直接利用离线的高德地图maps.js,流畅度甩别人一条街!而且那些高德地图的API你也可以用了!这简直太优秀了!

注意:

  1. getTileUrl瓦片地图地址,一定要用function,直接字符串,默认走https就404了
  1. 不要用defaultLayer来加载地图,会加载不了瓦片地图,要叠加一层layer
  1. 避免加载空白一定要限定缩放范围zooms和边界方位bounds

文件地址:public/offlineMap.html可测试验证离线地图


 <div id="container"></div>
    <script>
      function initMap() {
    
    
        var map = new AMap.Map('container', {
    
    
          zoom: 15,
          //下载范围的中心点
          center: [113.392987, 23.051086],
          zooms: [14, 15]
        });
        //一定要全地址,瓦片不走相对地址的
        let tileUrl = 'http://127.0.0.1:5500/public/tiles/[z]/[y]/[x].png';
        let xyzLayer = new AMap.TileLayer({
    
    
          // 瓦片地图地址,一定要用function,直接字符串,默认走https就404了
          getTileUrl: function (x, y, z) {
    
    
            return tileUrl.replace('[x]', x).replace('[y]', y).replace('[z]', z);
          },
          //限制缩放等级为下载的等级
          zooms: [14, 15],
          zIndex: 10,
          tileSize: 256
        });
        map.add(xyzLayer);
        let b = [113.353114, 23.02803, 113.43286, 23.074142];
        //限制范围,避免加载到空瓦片
        let bounds = new AMap.Bounds([b[2], b[3]], [b[0], b[1]]);

        map.setBounds(bounds);
        map.setLimitBounds(bounds);
      }
    </script>

效果

image.png

  • 上图是高德地图瓦片地图,下图是原来的高德地图,可以看到上面的字比平时使用的矢量高德地图大,颜色也有所不同的。

image.png

目前高德地图开放的瓦片地图样式只有卫星,交通,普通三种,样式上满足不了你的需求,这时候你只能手动css,通过filter属性对地图瓦片进行魔改。但是这个东东有点副作用,就是把地图上加载的矩形等其他元素也魔改了,因此改动样式需谨慎。

.amap-layer {
   
   
        filter: invert(100%);
      }

搜狗截图20230421220531.png

如果有耐心的UI,可以让UI批量手改样式(前提是你瓦片真的不多,否则会被UI爆头)

相关文章
|
3月前
|
前端开发 JavaScript Java
前端限制打包文件数量
前端限制打包文件数量
183 65
|
2月前
|
JavaScript 前端开发 Docker
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
在使用 Deno 构建项目时,生成的可执行文件体积较大,通常接近 100 MB,而 Node.js 构建的项目体积则要小得多。这是由于 Deno 包含了完整的 V8 引擎和运行时,使其能够在目标设备上独立运行,无需额外安装依赖。尽管体积较大,但 Deno 提供了更好的安全性和部署便利性。通过裁剪功能、使用压缩工具等方法,可以优化可执行文件的体积。
145 3
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
|
1月前
|
前端开发 API
前端界面生成PDF并导出下载
【10月更文挑战第21天】利用合适的第三方库,你可以在前端轻松实现界面生成 PDF 并导出下载的功能,为用户提供更方便的文档分享和保存方式。你还可以根据具体的需求进一步优化和定制生成的 PDF 文件,以满足不同的业务场景要求。
|
2月前
|
前端开发 JavaScript
💥【exceljs】纯前端如何实现Excel导出下载和上传解析?
本文介绍了用于处理Excel文件的库——ExcelJS,相较于SheetJS,ExcelJS支持更高级的样式自定义且易于使用。表格对比显示,ExcelJS在样式设置、内存效率及流式操作方面更具优势。主要适用于Node.js环境,也支持浏览器端使用。文中详细展示了如何利用ExcelJS实现前端的Excel导出下载和上传解析功能,并提供了示例代码。此外,还提供了在线调试的仓库链接和运行命令,方便读者实践。
417 5
|
2月前
|
JavaScript 前端开发 编译器
吐血整理:纯前端如何实现批量dom转图片,并下载成压缩包
【10月更文挑战第2天】吐血整理:纯前端如何实现批量dom转图片,并下载成压缩包
61 2
|
2月前
|
JSON 前端开发 JavaScript
前端模块打包器的深度解析
【10月更文挑战第13天】前端模块打包器的深度解析
|
2月前
|
存储 前端开发 JavaScript
前端模块化打包工具的深度解析
【10月更文挑战第13天】前端模块化打包工具的深度解析
|
2月前
|
前端开发 JavaScript 开发工具
从零开始:构建、打包并上传个人前端组件库至私有npm仓库的完整指南
从零开始:构建、打包并上传个人前端组件库至私有npm仓库的完整指南
387 0
|
2月前
|
资源调度 前端开发 安全
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
130 0
|
3月前
|
前端开发 开发者
在前端开发中,webpack 作为一个强大的模块打包工具,为我们提供了丰富的功能和扩展性
【9月更文挑战第1天】在前端开发中,Webpack 作为强大的模块打包工具,提供了丰富的功能和扩展性。本文重点介绍 DefinePlugin 插件,详细探讨其原理、功能及实际应用。DefinePlugin 可在编译过程中动态定义全局变量,适用于环境变量配置、动态加载资源、接口地址配置等场景,有助于提升代码质量和开发效率。通过具体配置示例和注意事项,帮助开发者更好地利用此插件优化项目。
88 13
下一篇
DataWorks