Trabalhando com GeoJSON no Node.js: uma introdução prática

GeoJSON é um formato padronizado para representar estruturas de dados geográficos com base em JSON. Existem muitas ferramentas excelentes para visualizar dados do GeoJSON. Além disso, esse formato é bom não apenas no armazenamento de coordenadas de certos pontos. Além de pontos, permite descrever outros objetos: linhas, polígonos, coleções de objetos.



Pontos - objetos de ponto


O ponto GeoJSON fica assim:

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

Este ponto representa um parque em Miami Beach, Flórida, EUA. Você pode visualizar facilmente esse ponto no mapa usando o projeto geojson.io .


Ponto no mapa

É importante observar que a coordenada na propriedade estácoordinatesescrita no formato[lng, lat]. A longitude no GeoJSON vem antes da latitude . Isso ocorre porque a longitude representa a direção leste-oeste (eixoxem um mapa típico) e a latitude representa a direção norte-sul (eixoyem um mapa típico). Os autores do GeoJSON procuraram manter a ordem das coordenadasx, y.

Um exemplo típico de uso de pontos GeoJSON é a geocodificação - traduzindo endereços como "429 Lenox Ave, Miami Beach, FL" em coordenadas expressas em longitude e latitude. Por exemplo, usamos a APIMapeamento de geocodificação. Para acessar esta API, uma solicitação HTTP deve ser feita no seguinte terminal:

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

Em resposta, o seguinte código virá:

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

Se você olhar atentamente para a resposta, acontece que features[0].geometryno código JSON é um ponto GeoJSON:

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


Visualização das coordenadas dos mapas estáticos da

API O Mapbox é uma ótima ferramenta para exibir pontos nos mapas. Abaixo está um script que decodifica a sequência passada e retorna o URL para a imagem que mostra o primeiro resultado da pesquisa.

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


Um exemplo de visualização de um ponto em um mapa

Linhas - objetos LineString


Nas linhas GeoJSON, os objetos LineStringrepresentam matrizes de coordenadas que descrevem uma linha em um mapa. A seguir, um objeto GeoJSON LineStringrepresentando a borda aproximada entre os estados da Califórnia e Oregon nos EUA:

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


Renderizando um LineString em um mapa As

linhas, usando uma API de navegação como o Mapbox , são usadas para renderizar um caminho passo a passo entre dois pontos. Uma maneira de representar uma estrada de um ponto[-80.139145,25.77409](escritório do WeWork Miami Beach) para um ponto[-80.2752743,25.7938434](Aeroporto Internacional de Miami) é usar um 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]
  ]
}

Objetos LineStringque são algumas rotas podem ser muito complexos. O objeto acima, por exemplo, descreve uma curta viagem de 15 minutos. É assim que tudo parece no mapa.


Caminho de um ponto para outro

Aqui está um script simples que retorna umaLineStringrepresentação do caminho entre 2 pontos usando a API dodirectionsMapbox.

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 de polígono


Os polígonos GeoJSON, objetos Polygon, são usados ​​para descrever áreas fechadas nos mapas. Podem ser áreas na forma de um triângulo, quadrado, dodecágono ou qualquer outra forma com um número fixo de lados. Por exemplo, o seguinte objeto GeoJSON descreve aproximadamente as fronteiras do estado do Colorado nos EUA:

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


Visualização de um polígono em um mapa

Os polígonos GeoJSON podem ser usados ​​para descrever formas muito complexas. Por exemplo, por algum tempo, o Uber usou o único campo de treinamento GeoJSON, que inclui os três principais aeroportos da área da Baía de São Francisco.


Polígono complexo do GeoJSON É

verdade que os polígonos do GeoJSON não podem representar círculos e elipses.

Para que são utilizados os polígonos? Geralmente - para descrever cercas geográficas . Por exemplo, imagine que você trabalha no Uber ou no Lyft. Você precisa mostrar aos usuários que reservam viagens a partir do aeroporto uma tela especial. Para fazer isso, você precisará descobrir se o ponto a partir do qual a viagem está reservada está dentro do intervalo que descreve o aeroporto (ou vários aeroportos, como na figura anterior).

Uma maneira de verificar se um ponto GeoJSON está dentro do polígono é usar o módulo Turpm npm. O módulo @turf/boolean-point-in-polygon permite descobrir se um ponto está dentro do 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));

O pacote Turf permite descobrir se um ponto está dentro do polígono usando o Node.js. Mas e se estivermos interessados ​​em obter as mesmas informações executando consultas no banco de dados? Nesse caso, você deve estar ciente de que a instrução$geoIntersects interna do MongoDB suporta o GeoJSON. Portanto, por exemplo, você pode escrever uma consulta que permita descobrir qual estado dos EUA corresponde a um determinado ponto no 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
}

Sumário


GeoJSON não é apenas o armazenamento de coordenadas de pontos. Você pode armazenar caminhos neste formato. Usando dados GeoJSON, você pode descobrir quando um usuário entrou na cerca geográfica. E, se necessário, o GeoJSON permite criar isócronas . Em torno do formato GeoJSON, um conjunto de ótimas ferramentas se formou. Portanto, o recurso geojson.io permite executar uma visualização simples de coordenadas no mapa. O projeto Mapbox fornece acesso a APIs geográficas avançadas. O pacote Turf permite executar computação geoespacial em navegadores e no Node.js.

O MongoDB suporta consultas relacionadas a dados geográficos. E se você armazenar as coordenadas geográficas dos pontos como pares de valores, sem usar o formato GeoJSON, isso significa que você está perdendo a oportunidade de usar algumas ótimas ferramentas de desenvolvimento.

Queridos leitores! Você usa o formato GeoJSON?


All Articles