近年来,地理信息系统 (GIS) 受到的广泛关注可能会让你认为它们是新鲜事物。事实上,早在 160 多年前,地理空间数据就在识别致命的 1854 年伦敦霍乱疫情 的源头方面发挥了重要作用。当地医生约翰·斯诺博士怀疑饮用水污染是疾病的根源。在调查期间,他绘制了霍乱病例的密度图,并采访了受影响社区的居民,了解他们的用水习惯。他的分析显示,公共水泵附近的发病率很高。
在本文中,我将介绍五个现代开源地图工具,并帮助你开始构建你的第一个 GIS 应用。
构建你的第一个 GIS 应用之前需要了解的 5 个工具
在深入了解如何构建你的第一个 GIS 应用(捷克共和国布拉格城堡地图)的教程之前,让我们先来看看五个可以简化你的地图制作生活的必备工具。
1. Create React App
如果你是 JavaScript 和 React 生态系统的新手,从头开始创建一个 React “Hello World” 应用对于胆小者来说并非易事。在你可以编写你的第一行 JavaScript 代码之前,需要组装多个库和配置。
幸运的是,Create React App 来解救你了。这款由 Facebook React 团队开发的命令行工具采用了“开箱即用”的方法,通过包含所有必要的库、入门文件,甚至单元测试框架,帮助你快速创建一个功能齐全的 React 应用。
2. GeoJSON.io
GeoJSON 是一种人类可读的格式,用于描述和共享 GIS 数据,并被许多地理空间库和应用程序广泛支持。GeoJSON.io 网站是你的 GeoJSON 数据的在线沙箱。
例如,你可以按如下方式描述比萨斜塔的位置
{
"type": "Feature",
"properties": {
"description": "Leaning Tower of Pisa"
},
"geometry": {
"type": "Point",
"coordinates": [10.39659, 43.72305]
}
}
要查看你的 GeoJSON 数据在地图上的外观,请访问 GeoJSON.io 并输入上述代码。

3. Leaflet
如果我可以将功劳归于一个开源库,因为它普及了 GIS 并将地理地图带入 Web 应用,那么这个奖项将授予 Leaflet.js。该库由 Vladimir Agafonkin 于 2012 年创建,此后已成为构建地图的事实上的开源 JavaScript 库。API 易于使用且文档完善,如果你遇到任何困难,Web 和 StackOverflow 上都有庞大的社区。

美国加利福尼亚州户外攀岩墙的热图。使用 Leaflet 和 Heatmap 插件构建。
4. Turf.js
Turf.js 是一个强大的地理空间库,可以包含在你的工具箱中。你可以执行常见的地理空间函数,例如测试一个点是否位于多边形内,或者执行更复杂的 k-means 计算,为热图准备数据。
例如,以下代码将计算旧金山和东京成田机场之间的距离
const fromSFO = turf.point([-122.3790, 37.6218]);
const toNRT = turf.point([140.3731, 35.7709]);
const options = {units: 'miles'};
var distance = turf.distance(fromSFO, toNRT, options);
5. OpenStreetMap
OpenStreetMap 由 Steve Coast 于 2004 年创立,是世界上最大的协作地图项目。与维基百科类似,该平台使像你我这样的人可以轻松地绘制我们周围的世界地图,方法是添加和标记当地的道路、高速公路、建筑物、河流等等。这些地图数据根据开放许可提供,是 GIS 应用的金矿!我们的教程应用将直接连接到 OpenStreetMap 的 REST API 服务器,以获取布拉格的所有城堡。商业用户可以下载其“每周地球文件”,这是其整个数据库的导出,一个大约 40GB 的数据文件。
Overpass-Turbo
Overpass-turbo 是一个交互式站点,用于尝试针对 OpenStreetMap 数据库的查询。要查看布拉格市中心 10 公里范围内的所有城堡,请输入以下查询,然后单击“运行”。请注意,地图不会自动缩放到我们的搜索结果。你必须在搜索框中输入“Prague”以使地图居中。
[out:json];
node[name="Praha"];
(
way[historic=castle](around:10000);
relation[historic=castle](around:10000);
);
out body;
>;
out skel qt;
构建你的第一个 GIS 应用
要学习如何构建 GIS 应用,让我们创建一个城堡探索器应用。
1. 使用 Create React App 创建应用
按照 Create React App 仓库中的 说明 创建一个可用的 React 应用。
# mkdir react-map
# cd react-map
# create-react-app .
这将生成一个新的项目结构。请注意以下两个文件,因为你需要在下一步中编辑它们。
- public/index.html: 应用程序的主 index.html
- src/App.js: React 组件的入口点
使用以下命令启动应用
# npm start

验证应用是否在你的浏览器中的 http://localhost:3000 上运行。
2. 设置 Leaflet 库和 React 包装器
接下来,将 Leaflet 和 React-Leaflet 引入项目。后者是一个包装器库,使 Leaflet 能够作为 React 组件工作。
使用以下命令安装 Leaflet 和 React-Leaflet
#npm install --save react-leaflet leaflet
在你的项目中找到 public/index.html
,并添加指向 leaflet.css
的链接,以及一些用于主 Leaflet div
的定位 CSS。地图将在此 div
容器内呈现。
<head>
...
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css"/>
<style>
.leaflet-container {
height: 650px;
width: 800px;
}
</style>
...
</head>
3. 创建第一个地图组件
在 Leaflet 中制作地图的方式在概念上类似于 GIMP 或 Photoshop 中图层的使用方式。要显示自定义数据(例如兴趣点标记),请将它们添加到 Leaflet 图层,然后将该图层添加到 Leaflet 地图。
render() {
return (
<Map >
<TileLayer url="tile server url"/>
<YourDataLayerComponent/>
</Map>
);
}
创建一个新的地图组件,并将地图中心放在捷克共和国布拉格。通过编辑 MyMap.js 如下所示,在市中心放置一个标记
src/MyMap.js
import React from "react";
import { Map, TileLayer, Marker } from "react-leaflet";
export default class MyMap extends React.Component {
constructor(props) {
super(props);
this.state = {
lat: 50.0893,
lng: 14.4284,
zoom: 12
};
}
render() {
const position = [this.state.lat, this.state.lng];
return (
<Map center={position} zoom={this.state.zoom}>
<TileLayer
attribution="&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[this.state.lat, this.state.lng]} />
</Map>
);
}
}
现在你可以通过简单地将 App.js 内容替换为以下内容,将 MyMap 组件连接到项目的入口点组件
src/App.js
import React, { Component } from "react";
import MyMap from "./MyMap";
class App extends Component {
render() {
return <MyMap />;
}
}
export default App;
你的浏览器现在应该显示布拉格地图!你可以使用鼠标缩放和平移地图。

在 CodePen 上查看:https://codepen.io/openbeta/pen/QmdvqP
4. 在地图上显示城堡
在此步骤中,你将提取在 OpenStreetMap 中标记为 historic=castle
的建筑物结构,并在你的地图上显示它们。你可以使用 query-overpass
库,而不是滚动你自己的 Rest API 客户端,该库从 OpenStreetMap 的 API 服务器 获取数据,使用以下命令
#npm i --save query-overpass
在 Castles.js 中为你的城堡组件创建一个新文件
src/Castles.js
import React from "react";
import { GeoJSON, Marker } from "react-leaflet";
import * as overpass from "query-overpass";
export default class Castles extends React.Component {
constructor(props) {
super(props);
this.state = {
geojson: undefined
};
}
componentDidMount() {
const query = `[out:json];(way[historic=castle](around:10000, 50.0874654,14.4212535);\
relation[historic=castle](around:10000, 50.0874654,14.4212535););\
out body;>;out skel qt;`;
const options = {
flatProperties: true
};
overpass(query, this.dataHandler, options);
}
dataHandler = (error, osmData) => {
if (!error && osmData.features !== undefined) {
this.setState({ geojson: osmData });
}
};
render() {
return this.state.geojson ? <GeoJSON data={this.state.geojson} /> : null;
}
}
在 MyMap.js 中将城堡组件添加到你的地图
src/MyMap.js
import Castles from "./Castles";
...
render() {
const position = [this.state.lat, this.state.lng];
return (
<Map center={position} zoom={this.state.zoom}>
<TileLayer
attribution="&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[this.state.lat, this.state.lng]} />
<Castles />
</Map>
);
}
codesandbox.io 上的完整项目 https://codesandbox.io/s/54l2kwrov4

codesandbox.io 上的完整项目 https://codesandbox.io/s/54l2kwrov4
下一步是什么?
如果你检查从 Overpass 返回的 JSON,你将看到大量信息,例如每个城堡的物理地址、捷克语名称、维基百科文章等等。你可以添加一个弹出窗口,以便在用户单击城堡时显示其他详细信息。
此外,该查询被硬编码为搜索布拉格市中心 10 公里半径内的城堡。你可以改进城堡组件和查询,以处理任意纬度和经度,从而有效地将该应用变成一个全球城堡探索器!
3 条评论