我按照一个指南在d3js中创建一个基本的美国地图。
指南链接- http:/bl.ocks.orgmichellechandra0b2ce4923dc9b5809922。.
我已经了解了GeoJSON和地图投影的基础知识。
目前我的地图是这样的--(地图1) - 这使用 d3.geoAlbersUsa()
投影
我希望我的地图是这样的--(地图2)。- 即上面不是弧形,而是直线的边界
联系 https:/www.worldatlas.comwebimagecountrysnamericausstatesusa50mer.htm
所需经费 -
我已经尝试过什么了
d3.geoMercator()
但阿拉斯加太大,无法放入视口,而且位于左上角,我不希望这样。你不能把Albers拉直。阿尔伯斯投影是一个圆锥投影--平行线的大小不一样,因为它们是投影到圆锥上的,这意味着会有一条曲线,因为投影的长度不一样(平行线在地球仪上的长度也不一样)。
圆柱形的墨卡托投影将较短的平行线拉伸到与赤道相同的宽度,这就是为什么在墨卡托投影中平行线是直的、水平的、长度相等的原因。
我们可以滥用Albers投影来熨平一些曲线,但d3的geoAlbersUsa投影是一个复合投影,不允许进行这样的修改。它实际上只是一个投影的集合。
相反,我们可以使用 d3.geoTransform 和 d3.geoMercator 创建我们自己的复合投影。结果应该是这样的。
这是一个简单的d3.geoTransform:
let projection = d3.geoTransform({
point: function(x, y) {
this.stream.point(x*2,y*2);
}
});
这只是将x和y的值乘以2, 它可以像这样传递给路径生成器: d3.geoPath(projection);
为了做一个复合投影,我们需要正确设置三个投影,然后正确地转化到地图上。我建立这些投影的时候是假设一个960x500的地图(类似于d3.geoAlbersUsa)。
let scale = 800;
let width = 960;
let height = 500;
let continental = d3.geoMercator()
.center([-98.58,39.83])
.translate([width*0.5,height*0.42]) // placed near center
.scale(scale);
let hawaii = d3.geoMercator()
.center([-157.25,20.8])
.scale(scale)
.translate([width*0.35,height*0.87]) // placed near bottom, slightly left of center
let alaska = d3.geoMercator()
.center([-152.5,65])
.translate([width*0.15,height*0.8]) // placed in lower left
.scale(scale*0.3)
Mercator在移动到极端纬度的时候会夸大面积,所以阿拉斯加,在地理上已经很大了(超过德克萨斯的两倍),变成了 很多 投影时太大。我已经把它缩小了,所以它是合适的(这样一来,它的尺寸大约是其他投影尺寸的110倍)。
我们还需要选择什么时候使用什么投影,所以根据一些规则,我们可以确定一个点是在阿拉斯加,夏威夷,还是在下层48。
let projection = d3.geoTransform({
point: function(x, y) {
if(y < 50 && x < -140) { // south and west : hawaii
this.stream.point(...hawaii([x,y]));
}
else if (y > 50) { // north : alaska
this.stream.point(...alaska([x,y]));
}
else { // otherwise, it's in the lower 48.
this.stream.point(...continental([x,y]));
}
}
});
就这样,我们有了三个投影和一个方法 来确定一个点应该使用哪一个投影。
我就把它全部捆绑为 d3.geoMercatorUsa()
以使其更加自如,我们得到。
// Composite Mercator projection for the US
d3.geoMercatorUsa = function() {
let scale = 800;
let width = 960;
let height = 500;
let continental = d3.geoMercator()
.center([-98.58,39.83])
.translate([width*0.5,height*0.42])
.scale(scale);
let hawaii = d3.geoMercator()
.center([-157.25,20.8])
.scale(scale)
.translate([width*0.35,height*0.87])
let alaska = d3.geoMercator()
.center([-152.5,65])
.translate([width*0.15,height*0.8])
.scale(scale*0.3)
let projection = d3.geoTransform({
point: function(x, y) {
if(y < 50 && x < -140) {
this.stream.point(...hawaii([x,y]));
}
else if (y > 50) {
this.stream.point(...alaska([x,y]));
}
else {
this.stream.point(...continental([x,y]));
}
}
});
return projection;
}
// Demonstration:
let width = 960;
let height = 500;
let svg = d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);
let path = d3.geoPath(d3.geoMercatorUsa());
d3.json("https://raw.githubusercontent.com/johan/world.geo.json/master/countries/USA.geo.json").then(function(data) {
svg.append("path")
.datum(data)
.attr("d",path);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>