D3 Web 地图:将栅格 PNG 与 TopoJSON 对齐
D3 Web Map: Align raster PNG with TopoJSON
我正在努力对齐加拿大的 topojson 和 PNG DEM。
我进行了大量搜索,并主要基于 https://gist.github.com/ThomasThoren/5e676d0de41bac8a0e96. My understanding is that the PNG must be preprojected and is simply scaled + translated to the appropriate spot on the page, while the topojson is either fed in as lat/long and reprojected with d3 tools or preprojected and drawn using d3.geoIdentity (as per https://medium.com/p/e9ccc6c0bba3/responses/show) 拼凑了一些测试。尽管我知道这两个数据集在投影坐标 space 中对齐(至少在预投影 topojson 并使用 d3.geoIdentity 时),但我还是无法对齐这两个数据集,这让我相信我在 d3 中遗漏了一些东西代码。有任何想法吗?如果这是解决方案,我在其他工具中操作 topojson 或源栅格没有问题,但我还没有找到适用于此对齐的方法。这是一个预投影 topojson 的示例。无论如何,无论我使用 geoConicConformal 在 d3 中进行预投影还是投影,我都会得到相同的结果。
这是 PNG file:
这是我的 TopoJSON file。
这是我用来显示 topojson 和 png 的代码:
<html>
<head>
<meta charset="utf-8">
<title>D3 Canada</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js"></script>
<script src="test-canada-topojson-canlam.js"></script>
<style>
body {
padding: 0;
margin: 0;
background: whitesmoke;
display: flex;
flex-direction: column;
align-items: center;
}
.province {
fill: white;
fill-opacity: 10%;
transition: fill 0.25s ease-in-out;
}
.province:hover {
fill: aliceblue;
fill-opacity: 90%;
transition: fill 0.25s ease-in-out;
}
</style>
</head>
<body>
<div class="home"></div>
<script>
var width = window.innerWidth,
height = window.innerHeight;
const container = d3.select(".home");
var svg = container.append("svg");
svg.attr("width", width)
.attr("height", height);
var provinces = topojson.feature(canada,canada.objects.canada).features;
var projection = d3.geoIdentity().reflectY(true).fitSize([width,height],topojson.feature(canada, canada.objects.canada));
var path = d3.geoPath(projection);
var bounds = path.bounds(topojson.feature(canada, canada.objects.canada));
var scale = 1 / Math.max((bounds[1][0] - bounds[0][0]) / width,(bounds[1][1] - bounds[0][1]) / height);
var raster_width = (bounds[1][0] - bounds[0][0]) * scale;
var raster_height = (bounds[1][1] - bounds[0][1]) * scale;
var rtranslate_x = (width - raster_width) / 2;
var rtranslate_y = (height - raster_height) / 2;
const g = svg.append("g");
g.append("image")
.attr("xlink:href", "canada-dem-conic.png")
.attr("class", "raster")
.attr("width", raster_width)
.attr("height", raster_height)
.attr("transform",
"translate(" + rtranslate_x + ", " + rtranslate_y + ")");
g.append("g")
.selectAll("path")
.data(provinces)
.enter()
.append("path")
.attr("d", path)
.attr("stroke", "lightslategrey")
.attr("stroke-width", 1.5)
.attr("stroke-linejoin","round")
.attr("class", "province")
</script>
</body>
</html>
以上结果:
我承认这比我希望的更令人沮丧。通常我会指出诸如 之类的答案。不幸的是,这实际上给了你已经使用过的投影:
var projection = d3.geoConicConformal()
.parallels([50,70])
.rotate([96,0])
.fitSize([width,height],geojson)
问题出在别处。
您的光栅像素似乎不是正方形:
当然它们呈现为正方形,但它们代表的面积为 5.7 平方公里乘 7.1 平方公里。
Spacing or cell size is the fixed distance in the x and y dimensions between each pixel in the raster. Some formats store only one spacing value, meaning that it must be the same for both the x and y dimensions – this is often referred to as square cells. source
但 D3 将像素视为正方形。如果我们使用以下方法拉伸您的图片:
var height = width / pixelWidth * pixelHeight
我们应该得到很好的对齐:
至少这看起来应该对齐。
这是该实现中最简单的 example。
当然,您可以压缩投影的 geojson 坐标而不是拉伸图像;然而,这比简单地缩放父容器更复杂(保留 fitSize 方法)。
我正在努力对齐加拿大的 topojson 和 PNG DEM。
我进行了大量搜索,并主要基于 https://gist.github.com/ThomasThoren/5e676d0de41bac8a0e96. My understanding is that the PNG must be preprojected and is simply scaled + translated to the appropriate spot on the page, while the topojson is either fed in as lat/long and reprojected with d3 tools or preprojected and drawn using d3.geoIdentity (as per https://medium.com/p/e9ccc6c0bba3/responses/show) 拼凑了一些测试。尽管我知道这两个数据集在投影坐标 space 中对齐(至少在预投影 topojson 并使用 d3.geoIdentity 时),但我还是无法对齐这两个数据集,这让我相信我在 d3 中遗漏了一些东西代码。有任何想法吗?如果这是解决方案,我在其他工具中操作 topojson 或源栅格没有问题,但我还没有找到适用于此对齐的方法。这是一个预投影 topojson 的示例。无论如何,无论我使用 geoConicConformal 在 d3 中进行预投影还是投影,我都会得到相同的结果。
这是 PNG file:
这是我的 TopoJSON file。
这是我用来显示 topojson 和 png 的代码:
<html>
<head>
<meta charset="utf-8">
<title>D3 Canada</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js"></script>
<script src="test-canada-topojson-canlam.js"></script>
<style>
body {
padding: 0;
margin: 0;
background: whitesmoke;
display: flex;
flex-direction: column;
align-items: center;
}
.province {
fill: white;
fill-opacity: 10%;
transition: fill 0.25s ease-in-out;
}
.province:hover {
fill: aliceblue;
fill-opacity: 90%;
transition: fill 0.25s ease-in-out;
}
</style>
</head>
<body>
<div class="home"></div>
<script>
var width = window.innerWidth,
height = window.innerHeight;
const container = d3.select(".home");
var svg = container.append("svg");
svg.attr("width", width)
.attr("height", height);
var provinces = topojson.feature(canada,canada.objects.canada).features;
var projection = d3.geoIdentity().reflectY(true).fitSize([width,height],topojson.feature(canada, canada.objects.canada));
var path = d3.geoPath(projection);
var bounds = path.bounds(topojson.feature(canada, canada.objects.canada));
var scale = 1 / Math.max((bounds[1][0] - bounds[0][0]) / width,(bounds[1][1] - bounds[0][1]) / height);
var raster_width = (bounds[1][0] - bounds[0][0]) * scale;
var raster_height = (bounds[1][1] - bounds[0][1]) * scale;
var rtranslate_x = (width - raster_width) / 2;
var rtranslate_y = (height - raster_height) / 2;
const g = svg.append("g");
g.append("image")
.attr("xlink:href", "canada-dem-conic.png")
.attr("class", "raster")
.attr("width", raster_width)
.attr("height", raster_height)
.attr("transform",
"translate(" + rtranslate_x + ", " + rtranslate_y + ")");
g.append("g")
.selectAll("path")
.data(provinces)
.enter()
.append("path")
.attr("d", path)
.attr("stroke", "lightslategrey")
.attr("stroke-width", 1.5)
.attr("stroke-linejoin","round")
.attr("class", "province")
</script>
</body>
</html>
以上结果:
我承认这比我希望的更令人沮丧。通常我会指出诸如
var projection = d3.geoConicConformal()
.parallels([50,70])
.rotate([96,0])
.fitSize([width,height],geojson)
问题出在别处。
您的光栅像素似乎不是正方形:
当然它们呈现为正方形,但它们代表的面积为 5.7 平方公里乘 7.1 平方公里。
Spacing or cell size is the fixed distance in the x and y dimensions between each pixel in the raster. Some formats store only one spacing value, meaning that it must be the same for both the x and y dimensions – this is often referred to as square cells. source
但 D3 将像素视为正方形。如果我们使用以下方法拉伸您的图片:
var height = width / pixelWidth * pixelHeight
我们应该得到很好的对齐:
至少这看起来应该对齐。
这是该实现中最简单的 example。
当然,您可以压缩投影的 geojson 坐标而不是拉伸图像;然而,这比简单地缩放父容器更复杂(保留 fitSize 方法)。