经纬志
首页 / 实战手册 / 数据加载

TopoJSON 丢了 transform,坐标全变成整数 7823

先看结论

文件从 20 MB 压到 3 MB,转换后却画不出任何东西,坐标是 7823、4210 这样的整数。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

用 topojson.feature(topology, topology.objects.districts) 转回 GeoJSON, 得到的坐标是 [7823, 4210]、[7826, 4208] 这样的整数, 而不是 [116.397, 39.909]。 地图上要么看不到内容,要么所有要素挤在 [0,0] 附近。

原始 TopoJSON 的顶层有 transform 字段,但被某个处理脚本删掉了, 或者经过了「只保留 objects 与 arcs」的裁剪。

原因

TopoJSON 为了压缩体积,把坐标量化成整数存储,并在顶层记录还原参数:

{
  "type": "Topology",
  "transform": { "scale": [0.001, 0.001], "translate": [73, 3] },
  "arcs": [...],
  "objects": { ... }
}

还原公式是 lon = x * scale[0] + translate[0], lat = y * scale[1] + translate[1]。 丢了 transform,topojson-client 只能原样返回量化整数。

排查过程

  1. 打印 TopoJSON 的顶层键,确认是否存在 transform。
  2. 打印 arcs[0][0],若为整数数组就是量化坐标。
  3. 看 objects 里有没有 bbox,可用它反推 translate。
  4. 与原始 GeoJSON 的 bbox 对比,若差值正好等于 scale × 量化值,即可确认。
console.log(Object.keys(topology));
// ['type', 'arcs', 'objects']            <- 缺 transform

console.log(topology.arcs[0][0]);
// [7823, 4210]                          <- 量化整数

const g = topojson.feature(topology, topology.objects.districts);
console.log(g.features[0].geometry.coordinates[0][0]);
// [7823, 4210]                          <- 未还原

解决方案

回到生成端重新导出,不要在转换脚本里删 transform。 确实只剩量化坐标时,可以用 bbox 反推参数。

# 用 topojson 命令行重新量化,保留 transform
npx topojson -q 1e4 -s 1e-3 -o districts.topo.json districts.geojson

# 检查输出是否带 transform
node -e "const t=require('./districts.topo.json');console.log(!!t.transform)"

前端兜底:已知原始数据范围时,手工补出 transform, 再交给 topojson.feature。

// 原始数据范围:经度 73~135,纬度 3~54;量化位宽由 arcs 最大值决定
const bbox = [73, 3, 135, 54];
const maxQ = 1e5;                                    // 量化系数
const scale = [(bbox[2] - bbox[0]) / maxQ, (bbox[3] - bbox[1]) / maxQ];
const translate = [bbox[0], bbox[1]];

const fixed = { ...topology, transform: { scale, translate } };
const geo = topojson.feature(fixed, fixed.objects.districts);
console.log(geo.features[0].geometry.coordinates[0][0]);
// [116.39743, 39.90923] 量级恢复正常

验证

还原后第一个坐标应落在经度 73~135、纬度 3~54 之间; 与原始 GeoJSON 抽样 10 个顶点比对,误差应小于 scale/2,即 0.00062 度(约 69 米)。

const c = geo.features[0].geometry.coordinates[0][0];
console.assert(c[0] > 73 && c[0] < 135 && c[1] > 3 && c[1] < 54, '坐标未还原');
console.assert(Math.abs(c[0] - 116.397428) < 0.001, '与原始值偏差过大');

适用版本

库 / 工具版本说明
TopoJSON 格式1.0transform 为可选,缺失时坐标为量化整数
topojson-client3.1.xfeature() 依赖 transform 还原
topojson-server / cli3.x-q 量化,-s 保留 transform
引用本文

经纬志(2026)。《TopoJSON 丢了 transform,坐标全变成整数 7823》。https://www.jingweizhi.com/cookbook/topojson-missing-transform.html(访问日期 2026-11-03)。