美文网首页GIS相关
使用JS代码对geoJSON地图文件压缩

使用JS代码对geoJSON地图文件压缩

作者: qs5639 | 来源:发表于2020-06-09 20:09 被阅读0次

    写在最前面

    1、推荐@HashTang 的原创文章 echarts地图边界数据的实时获取与应用,省市区县多级联动提供的思路和文件下载方式。需要的可以移步学习下

    2、geoJSON 都知道是存储坐标位置的地图文件,可以被ECharts解析。但体积很大,当项目需要全国地图(包括地市)时,但地图文件体积就很可怕了。

    3、使用Ecahrts未公开的压缩代码(parseGeoJson.js)进行修改

    一、先上结果(河南省全省geoJSON文件压缩比在87%左右)

    image

    二、实现思路

    echarts为了减少地图文件的大小,对polygon对象的坐标数组进行了压缩,压缩算法为ZigZag,坐标的二维数组压缩为一段字符串,增加属性encodeOffsets作为偏移初始,是坐标数组的第一个元素的1024倍。在装载地图的时候进行解码。

    echarts的源文件:https://github.com/ecomfe/echarts/blob/dc31c3fda747dbae549bfad34f8f84a9fd7864f7/src/coord/geo/parseGeoJson.js

    三、整理 parseGeoJson.js文件为无依赖的独立模块

    js文件中依赖太多,把不需要的代码给调整下,重命名
    1、去除相关图形依赖,全部按照geoJSON串方式处理
    2、export为独立模块,供JS代码引用
    3、参照见文章最后的 utils.js 代码块(篇幅太长,放在最后)

    四、具体用法

    将geoJSON串作为入参带入convert2Echarts,指定类型为“json”即可

    // 打包geoJSON到 zip.files  && 对geoJSON进行代码压缩
    // mapJson:已经存在的地图geoJSON串
    let zipMapJSON = this.$utils.convert2Echarts(JSON.stringify(mapJson), "", "json");
    
    // 通过saveAs.js将文件保存到本地(见 https://www.jianshu.com/p/c293c94d9ab7中的用法)
    this.zip.file(`${this.codeList[i].code}.geoJson`, zipMapJSON);
    

    五、utils.js文件源码(作为独立模块,可直接在项目中import使用)

    // utils.js
    /**
     * 通过echarts提供的算法对坐标进行转码
     * @param {JSONString} jsonSTR 需要压缩的JSON串
     * @param {String} fileName 文件名 
     * @param {String} type 以书面类型进行压缩 
     */
    function convert2Echarts(jsonSTR, fileName, type) {
        var results = "";
        var json = JSON.parse(jsonSTR);
        // Meta tag
        json.UTF8Encoding = true;
        var features = json.features;
        if (!features) {
            return;
        }
        features.forEach(function (feature) {
            var encodeOffsets = feature.geometry.encodeOffsets = [];
            var coordinates = feature.geometry.coordinates;
            if (feature.geometry.type === 'Polygon') {
                coordinates.forEach(function (coordinate, idx) {
                    coordinates[idx] = encodePolygon(
                        coordinate, encodeOffsets[idx] = []
                    );
                });
            } else if (feature.geometry.type === 'MultiPolygon') {
                coordinates.forEach(function (polygon, idx1) {
                    encodeOffsets[idx1] = [];
                    polygon.forEach(function (coordinate, idx2) {
                        coordinates[idx1][idx2] = encodePolygon(
                            coordinate, encodeOffsets[idx1][idx2] = []
                        );
                    });
                });
            }
        });
        if (type === 'json') {
            results = JSON.stringify(json);
        } else {
            results = addEchartsJsWrapper(JSON.stringify(json), fileName);
        }
        return results;
    };
    
    function encodePolygon(coordinate, encodeOffsets) {
        var result = '';
    
        var prevX = quantize(coordinate[0][0]);
        var prevY = quantize(coordinate[0][1]);
        // Store the origin offset
        encodeOffsets[0] = prevX;
        encodeOffsets[1] = prevY;
    
        for (var i = 0; i < coordinate.length; i++) {
            var point = coordinate[i];
            result += encode(point[0], prevX);
            result += encode(point[1], prevY);
    
            prevX = quantize(point[0]);
            prevY = quantize(point[1]);
        }
    
        return result;
    }
    
    // 以AMD的方式输出,并直接注册到echarts中
    function addEchartsJsWrapper(jsonStr, fileName) {
        return ['(function (root, factory) {',
            "   if (typeof define === 'function' && define.amd) {",
            "       define(['exports', 'echarts'], factory);",
            "   } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {",
            "       factory(exports, require('echarts'));",
            "   } else {",
            "       factory({}, root.echarts);",
            "   }",
            " }(this, function (exports, echarts) {",
            "       var log = function (msg) {",
            "           if (typeof console !== 'undefined') {",
            "               console && console.error && console.error(msg);",
            "           }",
            "       }",
            " if (!echarts) {",
            "       log('ECharts is not Loaded');",
            "           return;",
            "       }",
            " if (!echarts.registerMap) {",
            "       log('ECharts Map is not loaded')",
            "       return;",
            " }",
            "  echarts.registerMap('" + fileName + "'," + jsonStr,
            '  )}));'].join('\n');
    }
    
    // 核心代码
    function encode(val, prev) {
        // Quantization
        val = quantize(val);
        // var tmp = val;
        // Delta
        val = val - prev;
    
        if (((val << 1) ^ (val >> 15)) + 64 === 8232) {
            //WTF, 8232 will get syntax error in js code
            val--;
        }
        // ZigZag
        val = (val << 1) ^ (val >> 15);
        // add offset and get unicode
        return String.fromCharCode(val + 64);
        // var tmp = {'tmp' : str};
        // try{
        //     eval("(" + JSON.stringify(tmp) + ")");
        // }catch(e) {
        //     console.log(val + 64);
        // }
    }
    
    function quantize(val) {
        return Math.ceil(val * 1024);
    }
    
    // export
    export default{
        convert2Echarts
    }
    

    相关文章

      网友评论

        本文标题:使用JS代码对geoJSON地图文件压缩

        本文链接:https://www.haomeiwen.com/subject/qkvetktx.html