使用topomerge合并topojson会打乱缠绕顺序
Posted
技术标签:
【中文标题】使用topomerge合并topojson会打乱缠绕顺序【英文标题】:Merging topojson using topomerge messes up winding order 【发布时间】:2021-01-24 08:09:52 【问题描述】:我正在尝试创建一个自定义世界地图,其中国家被合并到区域中,而不是单独的国家。不幸的是,由于某种原因,整个过程中的缠绕顺序似乎有些混乱。
作为基础数据,我使用的是自然地球10m_admin_0_countries
可用的形状文件here。作为合并国家/地区的标准,我有一个如下所示的查找地图:
const countryGroups =
"EUR": ["ALA", "AUT", "BEL"...],
"AFR": ["AGO", "BDI", "BEN"...],
...
合并我正在使用的形状topojson-client。由于我希望获得比 CLI 命令提供的更高级别的控制,因此我编写了一个脚本。它遍历查找图并挑选出属于一个组的所有 topojson 特征并将它们合并为一个形状,并将生成的合并特征放入一个 geojson 框架中:
const topojsonClient = require("topojson-client");
const topojsonServer = require("topojson-server");
const worldTopo = topojsonServer.topology(
countries: JSON.parse(fs.readFileSync("./world.geojson", "utf-8")),
);
const geoJson =
type: "FeatureCollection",
features: Object.entries(countryGroups).map(([region, ids]) =>
const relevantCountries = worldTopo.objects.countries.geometries.filter(
(country, i) =>
ids.indexOf(country.properties.ISO_A3) >= 0
);
return
type: "Feature",
properties: region, countries: ids ,
geometry: topojsonClient.merge(worldTopo, relevantCountries),
;
),
;
到目前为止,一切都运行良好(据称)。当我尝试使用github gist(或任何其他可视化工具,如 vega lite)来可视化地图时,形状似乎都一团糟。我怀疑我在合并功能期间做错了什么,但我无法弄清楚它是什么。
当我尝试使用 CLI 执行相同操作时,它似乎工作正常。但由于我需要对合并进行更多控制,因此仅使用 CLI 并不是一个真正的选择。
【问题讨论】:
【参考方案1】:最后一个特征,称为“世界”,应该包含所有剩余个国家,但相反,它包含所有国家,句号。您可以在以下展示中看到这一点。
var w = 900,
h = 300;
var projection = d3.geoMercator().translate([w / 2, h / 2]).scale(100);
var path = d3.geoPath().projection(projection);
var color = d3.scaleOrdinal(d3.schemeCategory10);
var svg = d3.select('svg')
.attr('width', w)
.attr('height', h);
var url = "https://gist.githubusercontent.com/Flave/832ebba5726aeca3518b1356d9d726cb/raw/5957dca433cbf50fe4dea0c3fa94bb4f91c754b7/world-regions-wrong.topojson";
d3.json(url)
.then(data =>
var geojson = topojson.feature(data, data.objects.regions);
geojson.features.forEach(f =>
console.log(f.properties.region, f.properties.countries);
);
svg.selectAll('path')
// Reverse because it's the last feature that is the problem
.data(geojson.features.reverse())
.enter()
.append('path')
.attr('d', path)
.attr('fill', d => color(d.properties.region))
.attr('stroke', d => color(d.properties.region))
.on('mouseenter', function()
d3.select(this).style('fill-opacity', 1);
)
.on('mouseleave', function()
d3.select(this).style('fill-opacity', null);
);
);
path
fill-opacity: 0.3;
stroke-width: 2px;
stroke-opacity: 0.4;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.js"></script>
<script src="https://d3js.org/topojson.v3.js"></script>
<svg></svg>
要解决此问题,我会确保始终从列表中删除所有指定的国家/地区。从您的数据中,我看不出“世界”的定义位置,以及它是否包含地球上的所有国家,或者它是否是通配符分配。
无论如何,您应该能够通过从worldTopo
中删除所有匹配项来修复它:
const topojsonClient = require("topojson-client");
const topojsonServer = require("topojson-server");
const worldTopo = topojsonServer.topology(
countries: JSON.parse(fs.readFileSync("./world.geojson", "utf-8")),
);
const geoJson =
type: "FeatureCollection",
features: Object.entries(countryGroups).map(([region, ids]) =>
const relevantCountries = worldTopo.objects.countries.geometries.filter(
(country, i) =>
ids.indexOf(country.properties.ISO_A3) >= 0
);
relevantCountries.forEach(c =>
const index = worldTopo.indexOf(c);
if (index === -1) throw Error(`Expected to find country $c.properties.ISO_A3 in worldTopo`);
worldTopo.splice(index, 1);
);
return
type: "Feature",
properties: region, countries: ids ,
geometry: topojsonClient.merge(worldTopo, relevantCountries),
;
),
;
【讨论】:
感谢您的回答!我明白了,那么这里实际上可能有两个问题。我通过简单地删除“世界”功能解决了重叠的形状。但是,缠绕顺序问题(我假设)仍然存在。至少当我尝试使用 vega lite 可视化地图时,形状似乎是错误的,如您所见here。但是,当我使用您的 d3 脚本时,它是 correct。那么这可能是一个 vega lite 问题吗? 我没有Vega的经验,所以不能说 我尝试了一些解决方法,但即使只有一个功能,这个问题总是存在。肯定和vega有关,不管是设置还是别的,我都说不准以上是关于使用topomerge合并topojson会打乱缠绕顺序的主要内容,如果未能解决你的问题,请参考以下文章