GeoJSON — это стандартизованный формат представления географических структур данных, основанный на JSON. Существует множество замечательных инструментов для визуализации GeoJSON-данных. При этом данный формат хорош не только в деле хранения координат неких точек. Он, помимо точек, позволяет описывать и другие объекты: линии, полигоны, коллекции объектов.
GeoJSON-точка выглядит так:
Эта точка представляет парк в Майами-Бич, штат Флорида, США. Визуализировать эту точку на карте легко можно с помощью проекта geojson.io.
Точка на карте
Важно отметить, что координата в свойстве
Типичный пример использования точек GeoJSON — геокодирование — преобразование адресов наподобие «429 Lenox Ave, Miami Beach, FL» в координаты, выраженные долготой и широтой. Например, мы пользуемся API геокодирования Mapbox. Для обращения к этому API нужно выполнить HTTP-запрос к следующей конечной точке:
В ответ придёт такой код:
Если присмотреться к ответу, то окажется, что
Визуализация координат
API статических карт Mapbox — это отличный инструмент для вывода точек на картах. Ниже показан скрипт, который декодирует переданную ему строку и возвращает URL на изображение, которое показывает первый результат поиска.
Пример визуализации точки на карте
В GeoJSON линии, объекты
Визуализация объекта LineString на карте
Линии, при использовании API навигации наподобие Mapbox, применяются для визуализации поэтапного пути между двумя точками. Один из способов представления автомобильного пути из точки
Объекты
Путь из одной точки в другую
Вот — простой скрипт, который возвращает
GeoJSON-полигоны, объекты
Визуализация полигона на карте
GeoJSON-полигоны могут использоваться для описания очень сложных форм. Например, некоторое время в Uber использовался единственный GeoJSON-полигон, включающий в себя все 3 основных аэропорта области залива Сан-Франциско.
Сложный GeoJSON-полигон
Правда, надо отметить, GeoJSON-полигоны не могут представлять окружности и эллипсы.
Для чего используются полигоны? Обычно — для описания геозон. Например, представьте себе, что работаете в Uber или в Lyft. Вам нужно показать пользователям, заказывающим поездки из аэропорта, особый экран. Для того чтобы это сделать, нужно будет узнать, находится ли точка, из которой заказывают поездку, в пределах полигона, описывающего аэропорт (или несколько аэропортов как на предыдущем рисунке).
Один из способов проверки нахождения GeoJSON-точки в пределах полигона заключается в использовании npm-модуля Turf. Модуль
Пакет Turf позволяет узнать о том, находится ли точка в пределах полигона, пользуясь средой Node.js. Но что если нас интересует получение таких же сведений путём выполнения запросов к базе данных? В таком случае стоит знать о том, что встроенный оператор MongoDB
GeoJSON — это не только хранение координат точек. В этом формате можно хранить пути. С использованием GeoJSON-данных можно выяснить момент попадания пользователя в геозону. А если нужно, то GeoJSON даже позволяет создавать изохроны. Вокруг формата GeoJSON сформировался набор отличных инструментов. Так, ресурс geojson.io позволяет выполнять простые визуализации координат на карте. Проект Mapbox даёт доступ к продвинутым географическим API. Пакет Turf позволяет выполнять геопространственные вычисления в браузерах и в среде Node.js.
MongoDB поддерживает запросы, связанные с географическими данными. И если вы храните географические координаты точек в виде пар значений, не пользуясь форматом GeoJSON, это значит, что вы упускаете возможность воспользоваться некоторыми замечательными инструментами разработки.
Уважаемые читатели! Пользуетесь ли вы форматом GeoJSON?
Точки — объекты Point
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]]
}
Визуализация объекта LineString на карте
Линии, при использовании API навигации наподобие Mapbox, применяются для визуализации поэтапного пути между двумя точками. Один из способов представления автомобильного пути из точки
[-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
-представление пути между 2 точками с использованием API directions
Mapbox.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);
});
Полигоны — объекты Polygon
GeoJSON-полигоны, объекты
Polygon
, используются для описания замкнутых областей на картах. Это могут быть области, имеющие форму треугольника, квадрата, двенадцатиугольника, или любой другой фигуры с фиксированным количеством сторон. Например, следующий GeoJSON-объект грубо описывает границы штата Колорадо в США:{
"type": "Polygon",
"coordinates": [[
[-109, 41],
[-102, 41],
[-102, 37],
[-109, 37],
[-109, 41]
]]
}
Визуализация полигона на карте
GeoJSON-полигоны могут использоваться для описания очень сложных форм. Например, некоторое время в Uber использовался единственный GeoJSON-полигон, включающий в себя все 3 основных аэропорта области залива Сан-Франциско.
Сложный GeoJSON-полигон
Правда, надо отметить, GeoJSON-полигоны не могут представлять окружности и эллипсы.
Для чего используются полигоны? Обычно — для описания геозон. Например, представьте себе, что работаете в Uber или в Lyft. Вам нужно показать пользователям, заказывающим поездки из аэропорта, особый экран. Для того чтобы это сделать, нужно будет узнать, находится ли точка, из которой заказывают поездку, в пределах полигона, описывающего аэропорт (или несколько аэропортов как на предыдущем рисунке).
Один из способов проверки нахождения GeoJSON-точки в пределах полигона заключается в использовании npm-модуля Turf. Модуль
@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?