GIS相关

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

2020-06-09  本文已影响0人  qs5639

写在最前面

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
}
上一篇下一篇

猜你喜欢

热点阅读