在Node.js中使用GeoJSON:实用介绍

GeoJSON是一种标准化格式,用于表示基于JSON的地理数据结构。有很多很棒的工具可以可视化GeoJSON数据。而且,这种格式不仅在存储某些点的坐标方面是好的。除了点,它还允许您描述其他对象:直线,多边形,对象集合。



点-点对象


GeoJSON点看起来像这样:

{
  "type": "Point",
  "coordinates": [-80.1347334, 25.7663562]
}

这一点代表了美国佛罗里达州迈阿密海滩的一个公园您可以使用geojson.io项目轻松在地图上可视化此点


在地图上的点

务必注意,属性中的坐标以coordinates格式编写[lng, lat]GeoJSON中的经度先纬度这是因为经度代表东西方向(x典型地图上的),纬度代表南北方向(y典型地图上的)。GeoJSON作者试图保持坐标顺序x, y

使用GeoJSON点的一个典型示例是地理编码 -将“ 429 Lenox Ave,Miami Beach,FL”之类的地址转换为以经度和纬度表示的坐标。例如,我们使用 API对Mapbox进行地理编码。要访问此API,必须向以下端点发出HTTP请求:

https://api.mapbox.com/geocoding/v5/mapbox.places/429%20lenox%20ave%20miami.json?access_token=pk.eyJ1IjoibWF0dGZpY2tlIiwiYSI6ImNqNnM2YmFoNzAwcTMzM214NTB1NHdwbnoifQ.Or19S7KmYPHW8YjRz82v6g&cachebuster=1581993735895&autocomplete=true

作为响应,将提供以下代码:

{"type":"FeatureCollection","query":["429","lenox","ave","miami"],"features":[{"id":"address.8052276751051244","type":"Feature","place_type":["address"],"relevance":1,"properties":{"accuracy":"rooftop"},"text":"Lenox Avenue","place_name":"429 Lenox Avenue, Miami Beach, Florida 33139, United States","center":[-80.139145,25.77409],"geometry":{"type":"Point","coordinates":[-80.139145,25.77409]}, ...}

如果仔细查看答案,结果发现features[0].geometry在JSON代码中这是一个GeoJSON点:

{"type":"Point","coordinates":[-80.139145,25.77409]}




API静态地图坐标的可视化 Mapbox是在地图上显示点的绝佳工具。下面是一个脚本,该脚本对传递给它的字符串进行解码,并将URL返回到显示第一个搜索结果的图像。

const axios = require('axios');

async function search(str) {
  const geocoderUrl = 'https://api.mapbox.com/geocoding/v5/mapbox.places/' +
    encodeURIComponent(str) +
    '.json?access_token=' +
    'pk.eyJ1IjoibWF0dGZpY2tlIiwiYSI6ImNqNnM2YmFoNzAwcTMzM214NTB1NHdwbnoifQ.Or19S7KmYPHW8YjRz82v6g';

  const res = await axios.get(geocoderUrl).then(res => res.data);
  const point = res.features[0].geometry;

  return 'https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/' +
    'pin-l-1+333(' + point.coordinates[0] + ',' + point.coordinates[1] + ')/' +
    point.coordinates[0] + ',' + point.coordinates[1] +
    ',14.25,0,0/600x600/' +
    '?access_token=pk.eyJ1IjoibWF0dGZpY2tlIiwiYSI6ImNqNnM2YmFoNzAwcTMzM214NTB1NHdwbnoifQ.Or19S7KmYPHW8YjRz82v6g';
}

search('429 Lenox Ave, Miami Beach').then(res => console.log(res));


可视化地图上的点的示例

行-LineString对象


在GeoJSON线中,对象LineString代表描述地图上一条线的坐标数组。以下是一个GeoJSON对象,它LineString表示美国加利福尼亚州和俄勒冈州之间的大致边界:

{
  "type": "LineString",
  "coordinates": [[-124.2, 42], [-120, 42]]
}




使用诸如 Mapbox之类的导航API在地图上渲染LineString,用于渲染两点之间的逐步路径。表示从一个点[-80.139145,25.77409](迈阿密海滩的WeWork办公室)到一个点[-80.2752743,25.7938434](迈阿密国际机场)的道路的一种方法是使用GeoJSON对象LineString

{
  "type": "LineString",
  "coordinates": [
    [-80.139153, 25.774281],
    [-80.13829, 25.774307],
    [-80.142029, 25.774479],
    [-80.148438, 25.772148],
    [-80.151237, 25.772232],
    [-80.172043, 25.78116],
    [-80.177322, 25.787195],
    [-80.185326, 25.787212],
    [-80.189804, 25.785891],
    [-80.19268, 25.785954],
    [-80.202301, 25.789175],
    [-80.207954, 25.788721],
    [-80.223, 25.782646],
    [-80.231026, 25.78261],
    [-80.238007, 25.784889],
    [-80.246025, 25.784403],
    [-80.249611, 25.785175],
    [-80.253166, 25.786049],
    [-80.259262, 25.786324],
    [-80.264038, 25.786186],
    [-80.264221, 25.787256],
    [-80.264214, 25.791618],
    [-80.264221, 25.792633],
    [-80.264069, 25.795443],
    [-80.263397, 25.795652],
    [-80.263786, 25.794928],
    [-80.267723, 25.794926],
    [-80.271141, 25.794859],
    [-80.273163, 25.795704],
    [-80.275009, 25.796482],
    [-80.277481, 25.796461],
    [-80.278435, 25.795622],
    [-80.278061, 25.794088],
    [-80.275276, 25.793804]
  ]
}

LineString某些路线的 对象可能非常复杂。例如,以上目标描述了一段短短的15分钟车程。这就是它们在地图上的外观。


从一个点到另一个点的路径

这是一个简单的脚本,该脚本LineString使用directionsMapboxAPI返回两点之间的路径表示形式

const axios = require('axios');

async function directions(fromPt, toPt) {
  const fromCoords = fromPt.coordinates.join(',');
  const toCoords = toPt.coordinates.join(',');
  const directionsUrl = 'https://api.mapbox.com/directions/v5/mapbox/driving/' +
    fromCoords + ';' + toCoords + '?' +
    'geometries=geojson&' +
    'access_token=pk.eyJ1IjoibWF0dGZpY2tlIiwiYSI6ImNqNnM2YmFoNzAwcTMzM214NTB1NHdwbnoifQ.Or19S7KmYPHW8YjRz82v6g';

  const res = await axios.get(directionsUrl).then(res => res.data);
  return res.routes[0].geometry;
}

const wework = { type: 'Point', coordinates: [-80.139145,25.77409] };
const airport = { type: 'Point', coordinates: [-80.2752743,25.7938434] };

directions(wework, airport).then(res => {
  console.log(res);
});

多边形-多边形对象


GeoJSON多边形object Polygon用于描述地图上的封闭区域。这些可以是三角形,正方形,十二边形或任何其他具有固定边数的图形形式的区域例如,以下GeoJSON对象大致描述了美国科罗拉多州的边界:

{
  "type": "Polygon",
  "coordinates": [[
    [-109, 41],
    [-102, 41],
    [-102, 37],
    [-109, 37],
    [-109, 41]
  ]]
}


地图上

多边形的可视化 GeoJSON多边形可用于描述非常复杂的形状。例如,一段时间以来,Uber使用了唯一的GeoJSON训练场,其中包括旧金山湾地区的所有3个主要机场。


复杂的GeoJSON-polygon

是的,应该注意的是GeoJSON-polygons不能表示圆形和椭圆形。

多边形有什么用?通常-描述地理围栏。例如,假设您在Uber或Lyft工作。您需要向用户显示从机场预订行程的特殊屏幕。为此,您将需要确定预订旅行的地点是否在描述机场(或上图中的几个机场)的范围内。

验证GeoJSON点是否在多边形内的一种方法是使用 Turpm npm模块。该模块 @turf/boolean-point-in-polygon允许您确定点是否在多边形内。

const pointInPolygon = require('@turf/boolean-point-in-polygon').default;

const colorado = {
  "type": "Polygon",
  "coordinates": [[
    [-109, 41],
    [-102, 41],
    [-102, 37],
    [-109, 37],
    [-109, 41]
  ]]
};

const denver = {
  "type": "Point",
  "coordinates": [-104.9951943, 39.7645187]
};

const sanFrancisco = {
  "type": "Point",
  "coordinates": [-122.4726194, 37.7577627]
};

// true
console.log(pointInPolygon(denver, colorado));

// false
console.log(pointInPolygon(sanFrancisco, colorado));

Turf包允许您使用Node.js找出点是否在多边形内。但是,如果我们有兴趣通过执行对数据库的查询来获取相同的信息,该怎么办?在这种情况下,您应该意识到内置的MongoDB 语句$geoIntersects支持GeoJSON。因此,例如,您可以编写查询,以找出哪个美国州对应于地图上的某个点:

const mongoose = require('mongoose');

run().catch(err => console.log(err));

async function run() {
  await mongoose.connect('mongodb://localhost:27017/geotest', {
    useNewUrlParser: true,
    useUnifiedTopology: true
  });
  await mongoose.connection.dropDatabase();

  const State = mongoose.model('State', mongoose.Schema({
    name: String,
    location: mongoose.Schema({
      type: String,
      coordinates: [[[Number]]]
    })
  }));

  const colorado = await State.create({
    name: 'Colorado',
    location: {
      "type": "Polygon",
      "coordinates": [[
        [-109, 41],
        [-102, 41],
        [-102, 37],
        [-109, 37],
        [-109, 41]
      ]]
    }
  });

    const denver = {
    "type": "Point",
    "coordinates": [-104.9951943, 39.7645187]
  };

  const sanFrancisco = {
    "type": "Point",
    "coordinates": [-122.4726194, 37.7577627]
  };

  //     ?
  let res = await State.findOne({
    location: {
      $geoIntersects: { $geometry: denver }
    }
  });
  res.name; // 

  //     -?
  res = await State.findOne({
    location: {
      $geoIntersects: { $geometry: sanFrancisco }
    }
  });
  res; // null
}

摘要


GeoJSON不仅存储点的坐标。您可以使用这种格式存储路径。使用GeoJSON数据,您可以了解用户何时输入地理围栏。而且,如有必要,GeoJSON甚至还可以创建等时线。围绕GeoJSON格式,已经形成了一套出色的工具。因此,资源geojson.io允许对地图上的坐标执行简单的可视化。Mapbox项目提供对高级地理API的访问。Turf软件包使您可以在浏览器和Node.js中执行地理空间计算。

MongoDB支持与地理数据有关的查询。而且,如果您将点的地理坐标存储为值对,而不使用GeoJSON格式,则意味着您会错失使用一些出色的开发工具的机会。

亲爱的读者们!您是否使用GeoJSON格式?


All Articles