gpt4 book ai didi

d3.js - map 投影上的弯曲 geojson 多边形边缘

转载 作者:行者123 更新时间:2023-12-04 15:44:45 24 4
gpt4 key购买 nike

我正在尝试使用 d3.js 和 geojson 在不同的 map 投影上绘制矩形。映射的坐标看起来是正确的,但是边缘以一种奇怪的方式出现弯曲。我知道这可能与真实地球上的最短路径有关,但我想要的是边缘遵循投影的平行线/子午线刻度。有没有办法做到这一点?任何人都可以帮忙吗?

Example: Aitoff Projection
Example: Mercator
这是我正在使用的代码:

<!DOCTYPE html>
<html>

<head>
<title>World Map</title>
<meta charset="utf-8">

<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>

<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<style>
path {
fill: red;
stroke: #000;
stroke-width: .1px;
}
.graticule {
fill: none;
stroke: #000;
stroke-width: .2px;
}
.foreground {
fill: none;
stroke: #333;
stroke-width: 1.2px;
}

</style>
</head>

<body>
<svg width="960" height="600"></svg>
<script>
const svg = d3.select("svg")
const myProjection = d3.geoMercator()
const path = d3.geoPath().projection(myProjection)
const graticule = d3.geoGraticule()

const geojson = {

"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {
"color": "blue"
},
"geometry": {
"type": "Polygon",
"coordinates": [[[-80.0, 50.0], [-20.0, 50.0], [-20.0, -10.0], [-80.0, -10.0], [-80.0, 50.0]]]
} }
]
}
function drawMap(err, world) {
if (err) throw err

svg.append("g")
.selectAll("path")
.data(topojson.feature(world, world.objects.land).features)
.enter().append("path")
.attr("d", path);

svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);

svg.append("path")
.datum(graticule.outline)
.attr("class", "foreground")
.attr("d", path);

svg.append("g")
.selectAll("path")
.data(geojson.features)
.enter().append("path")
.attr("d", path)

}
d3.json("https://unpkg.com/world-atlas@1.1.4/world/50m.json", drawMap)


</script>
</body>

</html>

最佳答案

您的假设是正确的:d3 使用大圆距离来绘制线条:这意味着使用 d3 geoProjection 和 geoPath 的两点之间的任何路径都遵循这两点之间最短的真实世界路径。这意味着:

  • 无论投影如何,两点之间的相同路径与其他地理点和要素对齐
  • 那个反经络可以占
  • 生成的 map 更准确地描绘了线条。

  • 要绘制直线和/或平行线(子午线是落在它们上的两点之间的最短路径 - 因此路径已经遵循此路径,假设经纬网未旋转)有几种可能性。

    最简单的解决方案是使用像墨卡托这样的圆柱投影来创建自定义 geoTransform。与 d3.geoProjections 不同,d3.geoTransforms 不使用球面几何,而是使用笛卡尔数据。因此,它们不会沿线采样以创建曲线:这在处理笛卡尔数据时是不必要的。这允许我们在 geoTransform 中对 geojson 顶点使用球面几何,同时仍然在 map 上保持直线:
    var transform = d3.geoTransform({
    point: function(x, y) {
    var projection = d3.geoMercator();
    this.stream.point(...projection([x,y]));
    }
    });

    如下图所示:

    var projection = d3.geoMercator();

    var transform = d3.geoTransform({
    point: function(x, y) {
    var projection = d3.geoMercator();
    this.stream.point(...projection([x,y]));
    }
    });

    var color = ["steelblue","orange"]


    var geojson = {type:"LineString",coordinates:[[-160,60],[30,45]]};
    var geojson2 = {type:"Polygon",coordinates:[[[-160,60,],[-80,60],[-100,30],[-160,60]]]}

    var svg = d3.select("body")
    .append("svg")
    .attr("width",960)
    .attr("height",500);

    svg.selectAll(null)
    .data([projection,transform])
    .enter()
    .append("path")
    .attr("d", function(d) {
    return d3.geoPath().projection(d)(geojson)
    })
    .attr("fill","none")
    .attr("stroke",function(d,i) { return color[i]; } )
    .attr("stroke-width",1);

    svg.selectAll(null)
    .data([projection,transform])
    .enter()
    .append("path")
    .attr("d", function(d) {
    return d3.geoPath().projection(d)(geojson2)
    })
    .attr("fill","none")
    .attr("stroke",function(d,i) { return color[i]; } )
    .attr("stroke-width",2);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>


    橙色线使用变换,蓝色线使用普通墨卡托

    在某些情况下,您可以将投影的精度(用于调节自适应采样)设置为某个高得离谱的数字,这对某些线条有效,但由于反子午线切割等原因,这对其他线条无效:

    var projection = d3.geoMercator().precision(1000000);

    var transform = d3.geoTransform({
    point: function(x, y) {
    var projection = d3.geoMercator();
    this.stream.point(...projection([x,y]));
    }
    });

    var color = ["steelblue","orange"]


    var geojson = {type:"LineString",coordinates:[[-160,60],[30,45]]};
    var geojson2 = {type:"Polygon",coordinates:[[[-160,60,],[-80,60],[-100,30],[-160,60]]]}

    var svg = d3.select("body")
    .append("svg")
    .attr("width",960)
    .attr("height",500);

    svg.selectAll(null)
    .data([projection,transform])
    .enter()
    .append("path")
    .attr("d", function(d) {
    return d3.geoPath().projection(d)(geojson)
    })
    .attr("fill","none")
    .attr("stroke",function(d,i) { return color[i]; } )
    .attr("stroke-width",1);

    svg.selectAll(null)
    .data([projection,transform])
    .enter()
    .append("path")
    .attr("d", function(d) {
    return d3.geoPath().projection(d)(geojson2)
    })
    .attr("fill","none")
    .attr("stroke",function(d,i) { return color[i]; } )
    .attr("stroke-width",2);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>


    如果您想在非圆柱投影上绘制与平行线对齐的线,则这两种方法都不起作用。对于圆柱投影,平行线是直的。上述方法只会创建直线。如果平行线不是直线投影,例如 Aitoff,线将不会与经纬网对齐。

    要使一条线沿着平行线,您需要沿路径采样点,因为投影的平行线不会都是直线,并且平行线不会遵循大圆距离。因此,在这些情况下,默认投影和上述方法都不起作用。

    采样时,您需要将数据视为笛卡尔 - 基本上使用圆柱投影(Plate Carree)使线遵循平行线。

    关于d3.js - map 投影上的弯曲 geojson 多边形边缘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56403810/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com