【问题标题】:D3 Web Map: Align raster PNG with TopoJSOND3 Web 地图:将光栅 PNG 与 TopoJSON 对齐
【发布时间】:2020-11-13 19:47:36
【问题描述】:

我正在努力将加拿大的 topojson 和 PNG DEM 对齐。

我进行了很多搜索,并根据https://gist.github.com/ThomasThoren/5e676d0de41bac8a0e96 拼凑了一些测试。我的理解是,PNG 必须预先投影并简单地缩放 + 翻译到页面上的适当位置,而 topojson 要么以 la​​t/long 形式输入并使用 d3 工具重新投影,要么使用 d3.geoIdentity 预先投影和绘制(根据https://medium.com/p/e9ccc6c0bba3/responses/show)。尽管知道这两个数据集在投影坐标空间中对齐(至少在预投影 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>

以上结果:

【问题讨论】:

  • 你能分享一下topojson以及图像和任何关于它的投影和地理范围的元数据吗?
  • @AndrewReid 感谢您的回复。我添加了 PNG 文件和 TopoJSON 文件的原件,以及 PNG 元数据和坐标系信息的屏幕截图(TopoJSON 也是如此)。

标签: javascript d3.js map-projections


【解决方案1】:

我承认这比我想象的更令人沮丧。通常我会指出一个答案,例如this。不幸的是,这实际上给了您已经使用的投影:

var projection = d3.geoConicConformal()  
    .parallels([50,70])
    .rotate([96,0])
    .fitSize([width,height],geojson)

问题出在其他地方。

您的栅格像素似乎不是正方形:

它们当然是正方形的,但它们代表一个 5.7 公里乘 7.1 公里的区域。

间距或像元大小是光栅中每个像素之间在 x 和 y 维度上的固定距离。某些格式只存储一个间距值,这意味着 x 和 y 维度必须相同——这通常称为方形单元格。 source

但 D3 将像素视为正方形。如果我们使用以下方法拉伸您的图像:

var height = width / pixelWidth * pixelHeight

我们应该得到很好的对齐:

至少这看起来是应该对齐的。

这是该实现中最简单的example

当然,您可以压缩投影的 geojson 坐标而不是拉伸图像;然而,这比简单地缩放父容器更复杂(保留 fitSize 方法)。

【讨论】:

  • 啊,单元格大小..从来没有考虑过。由于非正方形大小是预处理的产物,我可以在那里而不是在浏览器中修复它。无论如何,感谢您的洞察力和详细的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-11
  • 2016-08-04
  • 2011-06-30
  • 2014-01-24
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
相关资源
最近更新 更多