Trabajando con GeoJSON en Node.js: una introducción práctica

GeoJSON es un formato estandarizado para representar estructuras de datos geográficos basados ​​en JSON. Existen muchas herramientas excelentes para visualizar datos GeoJSON. Además, este formato es bueno no solo en el almacenamiento de coordenadas de ciertos puntos. Además de los puntos, le permite describir otros objetos: líneas, polígonos, colecciones de objetos.



Puntos: objetos puntuales


El punto GeoJSON se ve así:

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

Este punto representa un parque en Miami Beach, Florida, EE. UU. Puede visualizar fácilmente este punto en el mapa utilizando el proyecto geojson.io .


Punto en el mapa

Es importante tener en cuenta que la coordenada en la propiedad estácoordinatesescrita en el formato[lng, lat]. La longitud en GeoJSON viene antes que la latitud . Esto se debe a que la longitud representa la dirección este-oeste (ejexen un mapa típico) y la latitud representa la dirección norte-sur (ejeyen un mapa típico). Los autores de GeoJSON buscaron mantener el orden de coordenadasx, y.

Un ejemplo típico de uso de puntos GeoJSON es la geocodificación , que traduce direcciones como "429 Lenox Ave, Miami Beach, FL" en coordenadas expresadas en longitud y latitud. Por ejemplo, usamos la APIGeocoding Mapbox. Para acceder a esta API, se debe realizar una solicitud HTTP al siguiente punto final:

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

En respuesta, vendrá el siguiente código:

{"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]}, ...}

Si observa de cerca la respuesta, resulta que features[0].geometryen el código JSON es un punto GeoJSON:

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


La visualización de las coordenadas de los mapas estáticos

API Mapbox es una gran herramienta para mostrar puntos en los mapas. A continuación se muestra un script que decodifica la cadena que se le pasa y devuelve la URL a la imagen que muestra el primer resultado de búsqueda.

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));


Un ejemplo de visualización de un punto en un mapa

Líneas: objetos LineString


En las líneas GeoJSON, los objetos LineStringrepresentan conjuntos de coordenadas que describen una línea en un mapa. El siguiente es un objeto GeoJSON que LineStringrepresenta el límite aproximado entre los estados de California y Oregon en los Estados Unidos:

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


Representación de un LineString en un mapa Las

líneas, utilizando una API de navegación como Mapbox , se utilizan para representar una ruta paso a paso entre dos puntos. Una forma de representar una carretera desde un punto[-80.139145,25.77409](oficina de WeWork Miami Beach) a un punto[-80.2752743,25.7938434](Aeropuerto Internacional de Miami) es usar un objeto GeoJSONLineString:

{
  "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]
  ]
}

Los objetos LineStringque son algunas rutas pueden ser muy complejos. El objeto anterior, por ejemplo, describe un viaje corto de 15 minutos. Así es como se ve todo en el mapa.


Ruta de un punto a otro

Aquí hay un script simple que devuelve unaLineStringrepresentación de la ruta entre 2 puntos utilizando la API dedirectionsMapbox.

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);
});

Polígonos - Objetos poligonales


Los polígonos GeoJSON, objetos Polygon, se usan para describir áreas cerradas en los mapas. Estas pueden ser áreas en forma de triángulo, cuadrado, dodecágono o cualquier otra forma con un número fijo de lados. Por ejemplo, el siguiente objeto GeoJSON describe aproximadamente los límites del estado de Colorado en los Estados Unidos:

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


La visualización de un polígono en un mapa Los

polígonos GeoJSON se pueden usar para describir formas muy complejas. Por ejemplo, durante algún tiempo Uber utilizó el único campo de entrenamiento GeoJSON, que incluye los 3 aeropuertos principales en el área de la Bahía de San Francisco.


Polígono GeoJSON complejo

Cierto, debe tenerse en cuenta que los polígonos GeoJSON no pueden representar círculos y elipses.

¿Para qué se usan los polígonos? Por lo general, para describir geofences . Por ejemplo, imagina que trabajas en Uber o en Lyft. Debe mostrar a los usuarios que reserven viajes desde el aeropuerto una pantalla especial. Para hacer esto, deberá averiguar si el punto desde el que se ordena el viaje se encuentra dentro del polígono que describe el aeropuerto (o varios aeropuertos como en la figura anterior).

Una forma de verificar que un punto GeoJSON está dentro del polígono es usar el módulo Turpm npm. El módulo le @turf/boolean-point-in-polygon permite averiguar si un punto está dentro del polígono.

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));

El paquete Turf le permite averiguar si un punto está dentro del polígono utilizando Node.js. Pero, ¿qué sucede si estamos interesados ​​en obtener la misma información ejecutando consultas en la base de datos? En este caso, debe tener en cuenta que la instrucción MongoDB incorporada es $geoIntersectscompatible con GeoJSON. Por lo tanto, por ejemplo, puede escribir una consulta que le permita averiguar qué estado de EE. UU. Corresponde a un determinado punto del mapa:

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
}

Resumen


GeoJSON no es solo almacenamiento de coordenadas de puntos. Puede almacenar rutas en este formato. Con los datos de GeoJSON, puede averiguar cuándo un usuario ingresó a la geovalla. Y si es necesario, GeoJSON incluso te permite crear isocronas . Alrededor del formato GeoJSON, se ha formado un conjunto de excelentes herramientas. Entonces, el recurso geojson.io le permite realizar una visualización simple de coordenadas en el mapa. El proyecto Mapbox proporciona acceso a API geográficas avanzadas. El paquete Turf le permite realizar computación geoespacial en navegadores y en Node.js.

MongoDB admite consultas relacionadas con datos geográficos. Y si almacena las coordenadas geográficas de puntos en forma de pares de valores, sin usar el formato GeoJSON, esto significa que pierde la oportunidad de usar algunas maravillosas herramientas de desarrollo.

¡Queridos lectores! ¿Utiliza el formato GeoJSON?


All Articles