目录
1概述
SaCa DataViz产品已经内置世界、中国、各省份直辖市、地市四个级别的地图数据,区县级以下(包括区县级)的地理数据则需要用户自己绘制或通过其他渠道获取。
地图资源文件存放路径为:dataviz[-web]\src\js\chartBuild\geojson\, 命名规则为行政区划编码.json,可百度或从中华人民共和国民政部官方网站 查询行政区划代码。
特殊的,世界地图对应地图资源文件为0.json,中国地图资源为1.json,省份地图保留前两位。
按照不同的使用场景,将需求划分为以下两类:
- 添加新的地图文件;
- 修改内置地图的形状;
声明: 在此强调,地图文件的获取并不属于SaCa DataViz产品本身责任提供的服务,以下所述只是提供一种方法需要用户独立完成,本团队不承担任何法律责任。
2添加新的地图文件
2.1获取地图geojson数据
2.1.1区县以上行政区划
区县级以上的地理数据可以在DataV.GeoAtlas 或开源渠道获取。
2.1.2区县及以下行政区划
以“昆明市官渡区”为例,访问http://ip:port/dataviz[-web]/src/mapPicker/mapPicker.html ,
按以下步骤操作:
1.先搜索官渡得到官渡的外轮廓(便于描绘)。
2.手动描绘官渡区下属的各个街道/乡镇。描绘一个街道完毕后双击鼠标左键,会弹出界面用于输入街道名称与区域代码,“确定”即可得到该街道描边数据。
3.重复2.依次绘制各个街道的轮廓,在右下角的窗口可以看到输出的数据。
如果有飞地的情况,需要在后期手动编辑合并飞地各个区块的MultiPolygon数据。
copy描边数据保存到一个json后缀的文件中,注意文件编码格式为UTF-8,建议使用标准行政区划代码命名文件。
2.2添加geojson文件及配置相关信息
将geojson文件放入dataviz-web\src\js\chartBuild\geojson\中。并在dataviz-web\common\config.js文件中找到regionCode对象,添加映射:
var regionCode = {
...
"官渡区":"530111",
...
}
“官渡区”:“530111”,前面为地理名称,后面为geojson文件名前缀。地理名称的命名并不随意(上卷下钻功能依赖准确的地名),必须匹配上级geojson文件内对应区域的地理名称。
2.3使用新添加的地图
注意: 前述config.js有更新,需要清浏览器缓存并刷新方能生效。
图表大类“地图”中五款地图都可以使用新扩展的geojson,在属性中逐级选择区域,如在省级选择“云南”、市级选择“昆明市”、区县级选择“官渡区”,如下图所示。
图2-3-1 选择并使用官渡区地图
3修改现有的地图区块
针对用户修改地图区块形状的需求,可以使用在线geojson编辑工具:
http://newgateway.gitee.io/xdh-map/case/geo-edit.html
或者
http://geojson.io/
上传geojson文件,编辑后下载。
4可能涉及的编码转换
4.1 坐标转换
(新增地图无此步骤)
如果使用的是Baidu的API获取到的地理信息数据,并且用户的需求是修改已有的地图数据,就必须把Baidu坐标转换WGS84坐标。具体为:先通过bd09togcj02()转换为GCJ09坐标,再通过gcj02towgs84()转换为WGS84坐标。算法如下:
function gcj02towgs84(*lng*, *lat*) {
var lat = +*lat*;
var lng = +*lng*;
var PI = 3.1415926535897932384626;
var dlat = transformlat(lng - 105.0, lat - 35.0);
var dlng = transformlng(lng - 105.0, lat - 35.0);
var radlat = lat / 180.0 \* PI;
var magic = *Math*.sin(radlat);
magic = 1 - ee \* magic \* magic;
var sqrtmagic = *Math*.sqrt(magic);
dlat = (dlat \* 180.0) / ((a \* (1 - ee)) / (magic \* sqrtmagic) \* PI);
dlng = (dlng \* 180.0) / (a / sqrtmagic \* *Math*.cos(radlat) \* PI);
var mglat = lat + dlat;
var mglng = lng + dlng;
return [lng \* 2 - mglng, lat \* 2 - mglat]
};
function bd09togcj02(*bd_lon*, *bd_lat*) {
var bd_lon = +*bd_lon*;
var bd_lat = +*bd_lat*;
var x_PI = 3.14159265358979324 \* 3000.0 / 180.0;
var x = bd_lon - 0.0065;
var y = bd_lat - 0.006;
var z = *Math*.sqrt(x \* x + y \* y) - 0.00002 \* *Math*.sin(y \* x_PI);
var theta = *Math*.atan2(y, x) - 0.000003 \* *Math*.cos(x \* x_PI);
var gg_lng = z \* *Math*.cos(theta);
var gg_lat = z \* *Math*.sin(theta);
return [gg_lng, gg_lat]
};
function transformlat(*lng*, *lat*) {
var lat = +*lat*;
var lng = +*lng*;
var PI = 3.1415926535897932384626;
var ret = -100.0 + 2.0 \* lng + 3.0 \* lat + 0.2 \* lat \* lat + 0.1 \* lng \*
lat + 0.2 \* *Math*.sqrt(*Math*.abs(lng));
ret += (20.0 \* *Math*.sin(6.0 \* lng \* PI) + 20.0 \* *Math*.sin(2.0 \* lng \*
PI)) \* 2.0 / 3.0;
ret += (20.0 \* *Math*.sin(lat \* PI) + 40.0 \* *Math*.sin(lat / 3.0 \* PI)) \*
2.0 / 3.0;
ret += (160.0 \* *Math*.sin(lat / 12.0 \* PI) + 320 \* *Math*.sin(lat \* PI /
30.0)) \* 2.0 / 3.0;
return ret
};
function transformlng(*lng*, *lat*) {
var PI = 3.1415926535897932384626;
var lat = +*lat*;
var lng = +*lng*;
var ret = 300.0 + lng + 2.0 \* lat + 0.1 \* lng \* lng + 0.1 \* lng \* lat + 0.1
\* *Math*.sqrt(*Math*.abs(lng));
ret += (20.0 \* *Math*.sin(6.0 \* lng \* PI) + 20.0 \* *Math*.sin(2.0 \* lng \*
PI)) \* 2.0 / 3.0;
ret += (20.0 \* *Math*.sin(lng \* PI) + 40.0 \* *Math*.sin(lng / 3.0 \* PI)) \*
2.0 / 3.0;
ret += (150.0 \* *Math*.sin(lng / 12.0 \* PI) + 300.0 \* *Math*.sin(lng / 30.0
\* PI)) \* 2.0 / 3.0;
return ret
};
4.2 压缩编码转换
如果需要修改内置的地图,找到对应的geojson文件的待修改区块,找到相应的coordinates字段。
如果coordinates字段后面有encodeoffset字段且不为空,则表明此coordinate为压缩后的字符串(例如下面),如果没有encodeoffset字段,则表明此coordinate数组未压缩,可以直接修改。
{"id":"810004","type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[["\@\@JBJAHBLCPAJCJDPCLOJM\@IBAFBBA\@CE\@AAE\@AAFIBQBADAFECCBEA\@GFCAYBABIRC\@QEGEACBEHMACECQACFE\`A\@GCK\@AFFHADMJBBF\@BB\@FBHCFI\@KLEBCAGWAAQDGCGJQHOPOHS\`KLN\@LDJAHETUDIJ\@HDxCZD"],["\@\@ACCBFB"],["\@\@D\@\@ACCCB\@CC\@CFBDJA"],["\@\@BA\@AG\@\@B\@BF\@"],["\@\@DABAGCADADBBDA"],["\@\@BAEBD\@"]],"encodeOffsets":[[[116946,22787]],[[116886,22776]],[[116934,22767]],[[117006,22758]],[[116932,22748]],[[116970,22738]]]},"properties":{"cp":[114.160023,22.245811],"name":"南区","childNum":6}}
修改压缩后的数组需要解压缩,解压缩算法如下decodePolygon(),参数与geojson中的字段匹配,encodeScale设为1024即可,解压缩后获得的经纬度数组即可直接修改。修改之后,还要把数组重新压缩,压缩算法为encodePolygon(),encodeOffsets字段与解压缩时相同即可。
function decodePolygon(*coordinate*, *encodeOffsets*, *encodeScale*) {
var result = [];
var prevX = *encodeOffsets*[0];
var prevY = *encodeOffsets*[1];
for (var i = 0; i \< *coordinate*.length; i += 2) {
var x = *coordinate*.charCodeAt(i) - 64;
var y = *coordinate*.charCodeAt(i + 1) - 64;
// ZigZag decoding
x = (x \>\> 1) \^ (-(x & 1));
y = (y \>\> 1) \^ (-(y & 1));
// Delta deocding
x += prevX;
y += prevY;
prevX = x;
prevY = y;
// Dequantize
result.push([x / *encodeScale*, y / *encodeScale*]);
}
return result;
}
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;
}
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);
}