我想绘制多个国家/地区,这些国家/地区的数据来自单独的topoJSON文件。这些国家/地区的地图应位于屏幕中央(居中),并设置适当的比例,以使地图填满整个窗口。
我已经尝试过的:
要获取每个国家/地区带有path.bounds(d)
的边界框,并分别在每个侧面(顶部,左侧,底部,右侧)使用最大值和最小值,并提供{{1}的均值中心}至path.centroid(d)
。这没用。
按照this解决方案中的建议应用projection.center()
或projection.fitExtent([[x0,y0],[x1,y1]],geojsonObject)
。在这里,我无法按所述方式创建featureCollection,并无法使用它来创建地图。
projection.fitSize([width,height],geojsonObject)
我认为,安德鲁·里德(Andrew Reid)在this帖子中以<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<style type="text/css">
.svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%;
vertical-align: top;
overflow: hidden;
}
.svg-content {
display: inline-block;
position: absolute;
margin: 0;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div id="container" class="svg-container"> </div>
<script type="text/javascript">
var width = 600; //for simplicity set to fixed value
var height = 600; //for simplicity set to fixed value
var projection = d3.geoMercator();
var path = d3.geoPath()
.projection(projection);
var svg = d3.select("#container").append("svg")
.classed("svg-content", true)
.attr("width", width)
.attr("height", height);
//Example data
var countries = ['germany', 'italy', 'switzerland', 'france'];
function loadJsonFiles() {
var files = ["https://api.myjson.com/bins/1b0ddz",
"https://api.myjson.com/bins/11jkvb",
"https://api.myjson.com/bins/96x1j",
"https://api.myjson.com/bins/sspzr"];
var promises = [];
var allCountryData = [];
files.forEach(function(url) {
promises.push(d3.json(url))
});
return Promise.all(promises)
.then(function(countryData) {
for (var i = 0; i < countryData.length; i++) {
allCountryData.push(countryData[i]);
}
return allCountryData;
});
}
loadJsonFiles().then(function(allCountryData) {
var allBounds = [];
var objName;
var countryData;
for (var i = 0; i < allCountryData.length; i++) {
objName = allCountryData[i].objects[countries[i]];
countryData = topojson.feature(allCountryData[i], objName);
//How can I use the right projection parameters for all country data loaded from topojson (outside the loop)?
projection
.scale(1000) //How to set this programmatically?
.center([8,47]) //How to set this programmatically?
.translate([width / 2, height / 2]);
//How can I append all the country data to the svg (outside the loop)?
svg.append("path")
.datum(countryData)
.attr("d", path);
}
});
</script>
</body>
</html>
或fitSize
提出的建议应该可以解决这个问题。但是我无法将其应用于我的问题。这也是我解决问题的首选方式。
或者,可以使用fitExtent
和center()
解决此问题吗?
我如何确定必须向scale()
提供哪些坐标以及向center()
提供值?
非常感谢您的帮助,我尝试了几天,但没有成功。
答案 0 :(得分:0)
projection.fitSize
和projection.fitExtent
都使用一个geojson对象,而不是一个geojson对象数组。幸运的是,geojson的对象类型可以包含所需的子对象:featureCollection
。
我看到您正在使用topojson,topojson.feature
返回了一个geojson对象。就您而言,每次使用topojson时,您都会返回一个功能集。
为了使用fitSize / fitExtent,我们需要创建一个包含所有单个要素的geojson对象,要素集合会执行此操作,其结构如下:
featureCollection = {
"type":"FeatureCollection",
"features": [ ... ]
}
我们可以使用以下内容构建要素集合:
var featureCollection = {type:"FeatureCollection","features":[]}
for (var i = 0; i < allCountryData.length; i++) {
objName = allCountryData[i].objects[countries[i]];
countryData = topojson.feature(allCountryData[i], objName);
featureCollection.features.push(...countryData.features)
}
现在我们可以通过
将此功能集传递给fitSize / fitExtentprojection.fitSize([width,height],featureCollection);
应如下所示:
var width = 400; //for simplicity set to fixed value
var height = 200; //for simplicity set to fixed value
var projection = d3.geoMercator();
var path = d3.geoPath()
.projection(projection);
var svg = d3.select("#container").append("svg")
.classed("svg-content", true)
.attr("width", width)
.attr("height", height);
//Example data
var countries = ['germany', 'italy', 'switzerland', 'france'];
function loadJsonFiles() {
var files = ["https://api.myjson.com/bins/1b0ddz",
"https://api.myjson.com/bins/11jkvb",
"https://api.myjson.com/bins/96x1j",
"https://api.myjson.com/bins/sspzr"];
var promises = [];
var allCountryData = [];
files.forEach(function(url) {
promises.push(d3.json(url))
});
return Promise.all(promises)
.then(function(countryData) {
for (var i = 0; i < countryData.length; i++) {
allCountryData.push(countryData[i]);
}
return allCountryData;
});
}
loadJsonFiles().then(function(allCountryData) {
var allBounds = [];
var objName;
var countryData;
var featureCollection = {type:"FeatureCollection","features":[]}
for (var i = 0; i < allCountryData.length; i++) {
objName = allCountryData[i].objects[countries[i]];
countryData = topojson.feature(allCountryData[i], objName);
featureCollection.features.push(...countryData.features)
}
projection.fitSize([400,200],featureCollection)
svg.selectAll("path")
.data(featureCollection.features)
.enter()
.append("path")
.attr("d",path);
});
svg {
border: 1px solid black;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<div id="container" class="svg-container"> </div>
除了使用了for循环(如上所示)创建功能集外,我保留了您的代码,并且没有循环通过附加每个路径,而是使用enter选择。最后,我更改了大小和位置,以使其更适合代码段视图。