TopoJSON 概述
TopoJSON是一种对地理拓扑进行编码的方式,它的名字来源于拓扑的英文topology,它的创始人正是D3的作者Mike Bostock。TopoJSON是GIS信息编码标准GeoJSON的扩展。要了解TopoJSON,先来看看GeoJSON。
GeoJSON
GeoJSON是一种格式,专门对多种地理数据结构进行编码。GeoJSON可以支持点、线、多边形、多点、多线、多个多边形等几何类型。特征对象是具有一些附加属性的几何对象。特征集合通常保存在FeatureCollection对象中。 - 摘自:geojson网站
如何理解FeatureCollection呢?举例说明,在描述世界地图的GeoJSON文件中,定义所有国家的对象就是一个FeatureCollection,而每一个国家则作为Feature对象包含在FeatureCollection中。
// FeatureCollection的结构
{
type: "FeatureCollection",
features:
[
{.....},
{.....}
]
}

上图的json对象是定义所有国家(地区)的FeatureCollection,其中的features描述了177个国家(地区),它是一个关于Feature对象的数组,Feature对象的结构如下。
// Feature的结构
{
type: "Feature",
id: 840,
properties: {},
geometry: {
type: "MultiPolygon",
coordinates: [
[
[-155.54135541355413, 19.08417463450381],
[-155.68895688956889, 18.91661133277394],
...
],
...
]
}
}
下图截取的是描述美国版图的Feature对象。

TopoJSON 和 GeoJSON 的比较
通过对GeoJSON的分析,可以了解到GeoJSON对于地图上的各种几何类型,都是以分离的形式存储的。比如北京市和河北省的边界有一部分是相同的,也就是说描述北京市和河北省的几何图形的边有一部分是重合的,GeoJSON只是独立的描述北京市和河北省,并不去考虑有一部分边相同的问题。而TopoJSON在GeoJSON的基础上,进行了优化,相同的边只会保存一份,这样就大大减小了冗余,TopoJSON的文件体积可以比GeoJSON小80%。
而因为TopoJSON进行了如上所述的优化,它的文件格式变得非常复杂,不像我们在上面列出的GeoJSON的FeatureCollection和Feature那么容易看懂。
在实际应用中,由于TopoJSON比GeoJSON的文件体积小得多,所以如果是在浏览器端使用,那么应该首选TopoJSON,以节省带宽,提高响应速度;如果是在服务器端使用,那么应该首选GeoJSON,因为其格式简单,通俗易懂。
TopoJSON API
从服务器端获取到的地理拓扑对象,基本都是TopoJSON格式的,但D3在JavaScript中是使用GeoJSON来处理地理要素的。因此,D3提供了一些API,可以在TopoJSON和GeoJSON之间进行转化。
topojson.feature(topology, object)
这个API用来返回GeoJSON的FeatureCollection或Feature。topology(参数1)通常是一个TopoJSON对象,object(参数2)是你想要返回的对象。
async function getEarth() {
// world是TopoJSON
const world = await d3.json(
"https://cdn.jsdelivr.net/npm/world-atlas@1/world/110m.json"
);
// countries 是GeoJSON的Feature类型的Array
const countries = topojson.feature(world, world.objects.countries).features;
}
上面的代码中,通过d3.json()请求TopoJSON数据,通过topojson.feature()将TopoJSON转换成GeoJSON。其中,topojson.feature(world, world.objects.countries)返回的就是上文中提到的FeatureCollection。
// FeatureCollection的结构
{
type: "FeatureCollection",
features:
[
{.....},
{.....}
]
}

topojson.mesh(topology[, object[, filter]])
这个API用来返回相连的几何体的边。通过mesh(网)这个词,我们可以想象这个API返回的就是一张网,它能够帮我们处理网中的相邻两个几何体的共有边,让这些共有边只保留一份。这在为整个网的边上色(stroke)的时候非常有用。
async function getEarth() {
// world是TopoJSON
const world = await d3.json(
"https://cdn.jsdelivr.net/npm/world-atlas@1/world/110m.json"
);
// border 是GeoJSON
const borders = topojson.mesh(
world,
world.objects.countries,
(a, b) => a !== b
);
}
项目在GitHub上的repo:github.com/dongqiaogon…
【完】