GeoJSON与GeoBuf的压缩解码


项目说明


问题描述

工作中前端项目开发偶尔会遇到echarts地图展示的需求,而地图文件的大小影响着请求的速度,用户网络稍慢一点,就会有展示延迟的问题;所以地图文件的压缩再传输是很有必要的;
网络上探索了一番,最后决定用Geobuf(https://github.com/mapbox/geobuf);


地图

获取地图途径很多,这里介绍几个常用的:

  • https://hxkj.vip/demo/echartsMap/
    此网站可以一次性打包所有的地图文件(geoJson格式),可以查看打包进度和查看打包失败的文件,我用的就是这个,但是有个问题是需要多尝试几次打包,再自行整理失败的文件,因为失败的概率挺大的,文件缺失的很多;

  • http://datav.aliyun.com/portal/school/atlas/area_selector
    阿里提供的自不用说,很好用,就是没有一次直接打包全部的方式,可自行写脚本跑一遍获取;

  • https://map.vanbyte.com/street.html
    这个网站可以一劳永逸,获取全部阿里云提供的地图文件,有压缩版,也很方便;准确性需自行考量;


压缩方案

压缩方法有很多,网上有通过后端Java进行压缩,前端直接请求压缩版的再开发;我换了个方式,利用node写个脚本跑一遍要压缩的文件就行了,项目里可直接获取压缩后的文件进行解码使用,当然啦,实际项目不一定要这样,要不前端打包会有些大 (:

利用express开发框架配合压缩工具

npm init
npm install express --save
  • 安装压缩工具:geobuf, pbf
npm install geobuf
npm install pbf
  • package.json 所有依赖项
"dependencies": {
    "express": "^4.18.2",
    "geobuf": "^3.0.2",
    "pbf": "^3.2.1"
 }
  • 建立 index.js 运行文件,放入地图文件等,文件列表如下
Demo
├─ index.js
├─ maps
│  ├─ compress	    // 预备存放压缩文件
│  └─ origin 		// 地图源文件
├─ package-lock.json
└─ package.json

  • index.js 代码如下:
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const port = 3000;
const targetFilePath = path.resolve('./maps/origin');

// 压缩工具
const geobuf = require('geobuf');
const Pbf = require('pbf');

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

/**
 * 压缩文件
 * @param {*} filePath 压缩前路径
 * @param {*} compressFilePath 压缩后路径
 */
function compressFile(filePath, compressFilePath) {
  fs.readFile(filePath, 'utf8', function (err, data) {
    const geojsonObj = JSON.parse(data.trim());
    let buffer = geobuf.encode(geojsonObj, new Pbf());

    fs.writeFile(compressFilePath, buffer, function (error) {
      if (error) {
        console.log('error:', error);
        console.info('--Error--:' + filePath);
      } else {
        console.info('--Success--:' + filePath);
      }
    });
  });
}

/**
 * 指定目录下的文件进行压缩
 * @param {*} filePath 指定路径
 */
function fileDisplayToCompress(filePath) {
  fs.readdir(filePath, function (err, files) {
    if (err) {
      return console.error('Error:(spec)', err);
    }

    files.forEach((filename) => {
      // 获取当前文件的绝对路径
      const filedir = path.join(filePath, filename);
      const realFilePath = filedir.split('\\maps\\origin\\')[1].replace(/\\/g, '/');
      const baseOriginPath =  'maps/origin/';
      const baseCompressPath = 'maps/compress/';

      // fs.stat(path)执行后,会将stats类的实例返回给其回调函数。
      fs.stat(filedir, (eror, stats) => {
        if (eror) {
          return console.error('Error:(spec)', err);
        }

        // 是否是文件
        const isFile = stats.isFile();
        // 是否是文件夹
        const isDir = stats.isDirectory();

        if (isFile) {
          const compressFilePath = realFilePath.replace(/geoJson/, 'geobuf.bpf');
          compressFile(baseOriginPath + realFilePath, baseCompressPath + compressFilePath);
        }

        if (isDir) {
          fs.mkdir(baseCompressPath + realFilePath, { recursive: true }, (err) => {
            if (err) throw err;
            fileDisplayToCompress(filedir);
          });
        }
      });
    });
  });
}

fileDisplayToCompress(targetFilePath);
  • 命令行运行 index.js
node index.js

运行后,/maps/compress下就是所有压缩版的地图文件,文件路径都是配套的,可自行修改测试~

压缩后的文件大概是源文件的1/5大小,压缩量还是非常可观的!


解码方案

既然有了一手的压缩文件,自然得通过解码才能供开发所用;

  • 新建项目,目录如下
    geobuf.js,pbf.js 文件可以在之前安装node_modules中获取;
    这里拿其中一个压缩文件 100000.geobuf.bpf 进行测试;
Demo
├─ index.html
├─ js
│  ├─ geobuf.js
│  └─ pbf.js
└─ maps
   └─ 100000.geobuf.bpf 	// 一个压缩版的地图文件

  • index.html 代码如下
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GeoJson | Geobuf</title>
</head>

<body>

  <script src="js/geobuf.js"></script>
  <script src="js/pbf.js"></script>
  <script>
    function getFile(name) {
      return fetch(`maps/${name}.geobuf.bpf`, {
        responseType: 'arraybuffer'
      }).then(res => {
        return res.arrayBuffer();
      }).then(data => {
        let geojson = geobuf.decode(new Pbf(data))
        console.info(geojson)	// geojson就是解码后的地图文件
      })
    }

    getFile('100000');
  </script>
</body>

</html>

总结

GeoBuf有很多好处:结构紧凑、文件小、方便编码和解码、能适用各种GeoJSON等等,开发者们可自行修改测试 (:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值