问题现象
抖音数据大屏要做中国地图下钻到各省的功能。用 DataV 下载的 GeoJSON 注册到 ECharts 之后,发现海南岛跑到了越南位置,东北部分地区也明显偏移。
原因分析
GeoJSON 的坐标系有两种:
- WGS84(EPSG:4326):GPS 用的坐标系,经纬度是真实的
- GCJ-02(火星坐标系):中国责令加密后的坐标系,国内地图服务(高德、腾讯)都在用
- BD-09:百度自己又加密了一层
DataV 的 GeoJSON 有的是 WGS84,有的是 GCJ-02,混着用就会出现偏移。ECharts 默认按 WGS84 渲染,数据源不对就偏了。
解决方案
方案一:统一用 GCJ-02 的 GeoJSON
去 DataV Atlas 下载时,选"高德地图"底图对应的 GeoJSON,这个就是 GCJ-02 的。
或者直接用 这个仓库 里整理好的 GCJ-02 版本中国地图数据。
方案二:坐标转换(万能但麻烦)
// WGS84 转 GCJ-02 的核心算法(简化版)
function wgs84ToGcj02(lng, lat) {
// 国内坐标才需要转换
if (!isInChina(lng, lat)) return [lng, lat];
const a = 6378245.0;
const ee = 0.00669342162296594323;
let dLat = transformLat(lng - 105.0, lat - 35.0);
let dLng = transformLng(lng - 105.0, lat - 35.0);
const radLat = lat / 180.0 * Math.PI;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
const sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * Math.PI);
dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * Math.PI);
return [lng + dLng, lat + dLat];
}
对每个 GeoJSON 的 coordinate 跑一遍这个转换,再注册到 ECharts。
方案三:直接用 ECharts 内置地图(最省事)
// ECharts 5.x 需要单独引入地图数据
import * as echarts from 'echarts';
import 'echarts/map/js/china.js'; // 需要安装 echarts-china-map
// 或者用量卷中国地图包
// npm install echarts-china-provinces-js
但这个方案自由度低,自定义区域(比如"华东地区"聚合)做不了。
✅ 我的最终选择:去 DataV Atlas 重新下载 GCJ-02 版本的 GeoJSON,替换掉原来的 WGS84 文件。10分钟解决,不需要写转换代码。
顺便解决的另一个坑
地图下钻时,ECharts 的 geo 和 series 要分开注册地图数据:
// 错误:只注册到 geo
echarts.registerMap('china', chinaJson);
// series 里的 map 类型会找不到
// 正确:geo 和 series 都能用
echarts.registerMap('china', chinaJson);
// 下钻到省也是同样方式
echarts.registerMap('guangdong', gdJson);
下钻时切换 series.data 里的 map 字段就行,不需要销毁重绘。