使用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倍。在装载地图的时候进行解码。
三、整理 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
}