D3 让地图变得简单
介绍
D3 是一个功能强大且灵活的 JavaScript 可视化库,其可视化效果不仅限于条形图和饼图。地理空间数据通常以地图形式呈现。D3 提供了完整的 API,用于在线可视化中生成、显示和与地理空间数据交互。本指南将介绍如何使用 D3 呈现在线地图。
成分
要使用 D3 中的地图,您需要了解三个概念:
- GeoJSON
- 预测
- 生成器
如果您一直在使用 D3,那么您会遇到用于制作形状的生成器。事实证明,D3 使用的生成器是形状生成器。它们是一种特殊的形状生成器,可将 GeoJSON 数据转换为 SVG 形状。但什么是 GeoJSON?
GeoJSON
您可能知道 JSON 是什么。您可能知道“Geo”意味着什么。因此,GeoJSON 是用 JSON 表示地理数据的标准也就不足为奇了。从 GeoJSON 开始,D3 可以创建表示地图的形状。有很多地方可以获取 GeoJSON 数据。最简单的方法之一是自己在 https://geojson.io 上生成它。
这个简单的界面可让您根据地图上绘制的形状生成 GeoJSON 数据。为了演示,请放大美国犹他州。
我选择犹他州有两个原因。首先,它是 Pluralsight 的所在地;其次,它的边界是直线,很容易绘制。现在,使用线条工具绘制该州的轮廓。要完成形状,请再次单击第一个点。在下图中,我从左上角开始,逆时针旋转。
完成的线称为特征,并存储在GeoJSON 中的features数组中。绘制线条时,坐标存储在 GeoJSON 中特征的coordinates键中。在properties键中,您可以添加特征的元数据,例如name。
Pluralsight 位于犹他州法明顿,就在盐湖城以北。放大到盐湖城(大盐湖东南)。您会在 15 号州际公路上看到法明顿。
使用标记工具在 Farmington 上放置标记并向 GeoJSON 添加另一个特征。
添加标识新特征的名称后,将 GeoJSON 保存到文件中。
预测
投影是一种函数,它获取 GeoJSON 文件中的纬度和经度坐标,并将其转换为 D3 可用于绘制形状的 xy 坐标。如果这听起来很难,那是因为它确实很难,但 D3 提供了许多函数来为您执行投影。
例如,墨卡托投影经常用于地图,因为恒定路径始终是直线。以下是使用墨卡托投影的犹他州 GeoJSON 的样子。
投影功能在d3 npm 包中可用。
import * as d3 from 'd3';
let projection = d3.geoMercator();
如果切换到等圆锥投影,形状会变形。但特征之间的相对面积是恒定的。
创建它的代码与前面的示例类似。
let projection = d3.geoConicEqualArea();
D3 中有大量投影。完整列表可从在线文档中获取。
生成器
生成器将使用 GeoJSON 中的特征根据投影创建形状。
d3.json("../data/utah.geojson").then(geodata => {
let projection = d3.geoConicEqualArea()
.fitSize([360, 480], geodata);
let generator = d3.geoPath().projection(projection);
d3.select("g.map")
.selectAll("path")
.data(geodata.features)
.join("path")
.attr("d", generator)
.attr('stroke', '#000')
.attr('fill', '#fff')
});
此代码生成了上一个示例。使用json函数读取 GeoJSON 数据。它还用于调整投影的几何形状,使其适合某个区域。使用geoPath方法创建生成器,并将投影应用于生成器。然后,您可以通过选择元素、传递 GeoJSON 中的特征并使用生成器将点的坐标提供给d属性来让 D3 创建地图。填充和描边属性是装饰性的。
命中测试
为了获得更准确的地图,网上有很多 GeoJSON 来源。这是从 Github 上的 PublicaMundi 存储库中的 GeoJSON 文件生成的美国地图。
地图可以交互。假设你想检查鼠标是否在州界内点击。获取鼠标点击的坐标很容易。
d3.select('g.map')
.on('mousedown', function() {
console.log(d3.mouse(this));
});
d3.mouse方法将返回相对于地图元素的 xy 坐标。问题是您可能需要纬度和经度。projection 函数将把 xy 坐标转换为纬度和经度。在 project 上调用invert将反转该过程。
d3.select('g.map')
.on('mousedown', function() {
console.log(projection.invert(d3.mouse(this)));
});
有了鼠标单击的经纬度,您现在需要获取州的边界并检查鼠标坐标是否在边界内。与地理空间分析中的许多任务一样,这很困难。但 D3 为您提供了一个 API 来简化这一过程。首先,您需要获取特征本身。特征只是对象,每个特征都有一个与州名称相对应的name属性。
var feature_utah = geodata.features.find(
f => f.properties.name === 'Utah'
);
要执行命中测试,请使用geoContains函数并向其传递特征和坐标。如果坐标在特征内,它将返回布尔值 true。
console.log(d3.geoContains(feature_utah, coords));
在鼠标单击的位置生成一个圆圈也很容易。geoCircle方法将在指定坐标处生成一个圆形。
var circle = d3.geoCircle()
.center(coords)
.radius(0.5);
圆圈代表一个 GeoJSON 对象,传递给生成器时将转换为 SVG路径字符串。该 SVG 可以附加到地图路径中。
d3.select('g.map')
.append('path')
.attr('d', generator(circle()));
结论
本指南向您展示了如何使用 GeoJSON 通过 D3 在 JavaScript 中呈现在线地图。D3 API 提供了对象和方法来处理复杂的地理空间分析工作。如您所见,创建地理空间可视化的部分挑战在于获取准确的地图数据。网上有很多存储库和数据库,您可以从中获取 GeoJSON 数据。您还可以将其他格式(包括 Shapefile)转换为 GeoJSON。
您还了解了投影如何允许您在 2d 坐标和纬度与经度之间进行转换。这使得创建交互式地理空间可视化成为可能。您了解了如何检查某个点是否包含在 GeoJSON 特征中,以及如何通过生成 GeoJSON 对象并将其添加到 SVG 路径来向地图添加形状。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~