【问题标题】:Let's make a TopoJSON map and view it with D3.js让我们制作一个 TopoJSON 地图并使用 D3.js 查看它
【发布时间】:2020-10-01 14:34:31
【问题描述】:

我制作了以下 TopoJSON 文件:https://gofile.io/d/CKBGhF

我想用一个基本的 D3.js 脚本在我的浏览器中查看它。从https://bost.ocks.org/mike/map/ 我找到了一个关于脚本的小教程。但是因为我的地图是由转换为 TopoJSON 的矢量制成的,所以它没有真正的坐标。使用 QGIS,我首先将其保存为 GeoJSON,然后使用 mapshaper 将其保存为 TopoJSON。

我应该如何查看我的地图?坐标或缩放比例完全错误吗?还是我的TopoJSON不好?

我的 HTML/Javascript 代码(我只更改了文件名):

<!DOCTYPE html>
<meta charset="utf-8">
<style>

/* CSS goes here. */

</style>
<body>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>

var width = 960,
    height = 1160;

var projection = d3.geo.mercator()
    .scale(500)
    .translate([width / 2, height / 2]);

var path = d3.geo.path()
    .projection(projection);

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

d3.json("topojson_mapshaper.json", function(error, uk) {
  svg.append("path")
      .datum(topojson.feature(uk, uk.objects.subunits))
      .attr("d", path);
});

</script>

【问题讨论】:

    标签: d3.js geojson topojson


    【解决方案1】:

    在我的回复中,我将所有代码升级到 d3v5,因为包含了自 d3v4 以来有助于绘制此数据的新功能(例如 d3.geoIdentityprojection.fitSize)。从 D3 v4 开始,D3 命名空间发生了一些变化(d3.geo.pathd3.geo.projectionName 现在是 d3.geoPathd3.geoProjectionName)。而在 D3v5 中,d3.json 现在返回 promise。

    这里有一些事情在起作用。

    Topojson.feature

    首先,D3只用d3.geoPath绘制geojson对象,D3不直接绘制topojson。因此,您的数据虽然存储为 topojson,但会在此处转换为 geojson:

    topojson.feature(uk, uk.objects.subunits)
    

    但是,您的 topojson 数据 uk 没有包含要素的 subunits 属性。相反,您有一个名为 test 的子单元属性:

     ...463908,4.10162]},"objects":{"test":{"type":"GeometryCollection"...
    

    通常诸如 mapshaper 之类的平台将源文件的文件名应用为子属性名称,所以我猜你从 QGIS 导出的源文件是 test.geojson 或类似的东西。

    如果我们登录:

    console.log(topojson.feature(uk, uk.objects.test))
    

    我们看到了有效的 geojson。现在我们有了geojson,我们可以绘制它了。

    坐标

    至于坐标系,topojson默认保留原坐标系。转换回 geojson 时,您的坐标将与原始坐标相同。因此,除非您的源数据没有实际坐标,否则“它没有真实坐标”的说法是不正确的。

    然而,您可以在生成 topojson 时从命令行或使用 mapshaper 投影或重新投影点。看来您已经在点上应用了投影,因为当我将您的 topojson 转换为 geojson 时,我看到的坐标看起来像像素值(单位不太可能是从 QGIS 导出的原始坐标)。

    如果使用投影坐标(笛卡尔点,而不是经纬度对,无论单位是米还是像素),我们不能使用 D3 geoProjection:这些采用 3D 点并将它们投影到平面上。

    由于您的值看起来像像素值,我们可以将您的数据直接传递给空投影:

    var path = d3.geoPath()
    

    或者,更明确地说:

    var path = d3.geoPath(null);
    var path = d3.geoPath().projection(null);
    

    在 D3v3 及更早版本中,需要明确设置

    这不会对 geojson 中的坐标进行任何转换。它将每个 geojson 坐标视为像素坐标并相应地绘制您的特征 (example)

    但是,如果我们的功能的投影范围与 SVG/Canvas 范围不匹配,则该选项将无用。相反,我们可以使用geoTransformgeoIdentity 来应用适当的转换。

    geoIdentity 选项是最简单的,因为它提供了方便的 fitSize 方法,可以让我们自动将 geojson 调整为 SVG/Canvas 尺寸(fitExtent 允许指定边距,而 fitSize 假定没有边距)。所有这些选项都可以作为投影传递给 d3.geoPath (example, full screen)。

    最后一个示例应该向您展示如何绘制数据。除非您只想显示边框,否则您大多有线串,这将使填充功能变得困难。

    进一步阅读

    根据以往的经验,有几个相关的问题浮现在脑海中:

    这个问题解决了关于预投影几何的可能问题,因为您似乎已经为屏幕尺寸预投影了几何。这带来了对齐挑战,权衡的是更快的渲染时间。

    这个问题涉及预先投影的几何图形以及将特征拟合到屏幕上。它对fitSizefitExtentgeoTransform 有更深入的了解。

    【讨论】:

      猜你喜欢
      • 2013-09-21
      • 2016-08-04
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多