Валидация координат

В работе с Mapbox GL JS координаты представляют собой фундаментальную единицу геопространственных данных. Библиотека оперирует стандартом WGS84, где каждая точка задаётся парой чисел: долгота (longitude) и широта (latitude). Порядок имеет принципиальное значение: [lng, lat], а не наоборот.

Любая операция отображения, трансформации или взаимодействия с картой в конечном итоге зависит от корректности этих значений. Ошибки в координатах приводят к некорректному позиционированию маркеров, искажению границ, сбоям при расчёте области видимости и невозможности корректного рендера геометрии.


Форматы координат и их интерпретация

В экосистеме Mapbox GL JS используются несколько форматов представления координат:

1. Точка (Point)

const point = [lon, lat];

2. GeoJSON формат

const feature = {
  type: "Feature",
  geometry: {
    type: "Point",
    coordinates: [lon, lat]
  },
  properties: {}
};

3. Массивы координат (LineString, Polygon)

const line = {
  type: "Feature",
  geometry: {
    type: "LineString",
    coordinates: [
      [lon1, lat1],
      [lon2, lat2]
    ]
  }
};

Ошибки чаще всего возникают при смешении форматов или нарушении порядка координат, особенно при интеграции сторонних API.


Базовые принципы валидации координат

Валидация координат включает несколько уровней проверки:

Проверка типа данных

Координаты должны быть числами:

function isNumber(value) {
  return typeof value === 'number' && Number.isFinite(value);
}

Некорректные значения:

  • NaN
  • Infinity
  • строки ("50.5")
  • null и undefined

Проверка структуры массива

Для точки:

function isValidPoint(coord) {
  return (
    Array.isArray(coord) &&
    coord.length === 2 &&
    isNumber(coord[0]) &&
    isNumber(coord[1])
  );
}

Диапазон допустимых значений

Географическая система координат ограничена физическими пределами:

  • Долгота (lng): от -180 до 180
  • Широта (lat): от -90 до 90

Проверка диапазона

function inBounds(lng, lat) {
  return (
    lng >= -180 && lng <= 180 &&
    lat >= -90 && lat <= 90
  );
}

Комбинированная проверка

function isValidLngLat(coord) {
  return (
    isValidPoint(coord) &&
    inBounds(coord[0], coord[1])
  );
}

Типичные ошибки при работе с координатами

Перепутанный порядок lat/lng

// Ошибка
const coord = [lat, lng];

// Правильно
const coord = [lng, lat];

Такая ошибка приводит к смещению точки в другую часть мира, часто в океан или на другой континент.


Строковые значения координат

const coord = ["50.4501", "30.5234"];

Mapbox GL JS не приводит типы автоматически. Такие данные проходят проверку в API некоторых источников, но ломают вычисления внутри библиотеки.


Частично заполненные координаты

const coord = [30.5]; // отсутствует широта

Некорректные границы

const coord = [200, 95]; // полностью вне диапазона

Валидация GeoJSON-структур

GeoJSON требует строгого соблюдения структуры. При работе с источниками данных в Mapbox GL JS это критично.

Проверка Feature Point

function validateFeature(feature) {
  return (
    feature &&
    feature.type === "Feature" &&
    feature.geometry &&
    feature.geometry.type === "Point" &&
    isValidLngLat(feature.geometry.coordinates)
  );
}

Проверка LineString

function isValidLineString(feature) {
  return (
    feature.geometry.type === "LineString" &&
    Array.isArray(feature.geometry.coordinates) &&
    feature.geometry.coordinates.every(isValidLngLat)
  );
}

Проверка Polygon

Полигон содержит массив массивов координат:

function isValidPolygon(feature) {
  return (
    feature.geometry.type === "Polygon" &&
    Array.isArray(feature.geometry.coordinates) &&
    feature.geometry.coordinates.every(
      ring => Array.isArray(ring) && ring.every(isValidLngLat)
    )
  );
}

Валидация перед использованием методов Mapbox GL JS

Многие методы библиотеки требуют строго валидные координаты.

setLngLat

marker.setLngLat(coord);

Если передать некорректные данные:

  • маркер может не отобразиться
  • может возникнуть ошибка рендера
  • поведение становится неопределённым

fitBounds

map.fitBounds([
  [minLng, minLat],
  [maxLng, maxLat]
]);

Валидация границ:

function isValidBounds(bounds) {
  return (
    Array.isArray(bounds) &&
    bounds.length === 2 &&
    isValidLngLat(bounds[0]) &&
    isValidLngLat(bounds[1])
  );
}

Защита от NaN и числовых артефактов

Частая проблема — результат арифметических операций:

const lat = parseFloat(value);
const lng = parseFloat(value2);

Если value некорректен:

parseFloat("abc") // NaN

Такие данные необходимо фильтровать до попадания в Mapbox GL JS.


Нормализация координат

В некоторых случаях координаты требуют приведения к допустимому диапазону.

Нормализация долготы

function normalizeLng(lng) {
  return ((lng + 180) % 360) - 180;
}

Ограничение широты

function clampLat(lat) {
  return Math.max(-90, Math.min(90, lat));
}

Проверка массивов координат высокой размерности

Для больших геометрий (например, маршрутов или границ стран) важно учитывать глубину вложенности.

function validateDeepCoordinates(coords) {
  if (!Array.isArray(coords)) return false;

  if (typeof coords[0] === "number") {
    return isValidLngLat(coords);
  }

  return coords.every(validateDeepCoordinates);
}

Защита при работе с внешними API

Данные из внешних сервисов часто не гарантируют корректность:

  • отсутствует порядок координат
  • смешаны форматы GeoJSON и массивов
  • присутствуют строки вместо чисел

Фильтрация входных данных

function sanitizeCoordinates(data) {
  if (!Array.isArray(data)) return null;

  const lng = Number(data[0]);
  const lat = Number(data[1]);

  if (!isFinite(lng) || !isFinite(lat)) return null;
  if (!inBounds(lng, lat)) return null;

  return [lng, lat];
}

Проверка данных перед добавлением источников

При добавлении источника данных в Mapbox GL JS:

map.addSource("points", {
  type: "geojson",
  data: geojson
});

некорректные координаты могут привести к:

  • пропуску объектов рендеринга
  • ошибкам в консоли
  • частичной отрисовке слоя

Предварительная фильтрация FeatureCollection

function filterValidFeatures(collection) {
  return {
    ...collection,
    features: collection.features.filter(validateFeature)
  };
}

Обработка пограничных случаев

Координаты на меридиане ±180°

const edge = [180, 0];

Такие точки требуют осторожности при интерполяции линий.


Полюса

const northPole = [0, 90];
const southPole = [0, -90];

Некоторые проекции и визуализации могут искажать геометрию в этих областях.


Пересечение антимеридиана

LineString, пересекающий ±180°, может требовать разбиения:

function crossesAntimeridian(coord1, coord2) {
  return Math.abs(coord1[0] - coord2[0]) > 180;
}

Практика безопасной работы с координатами

Стабильная работа с геоданными в Mapbox GL JS строится на последовательной проверке:

  • тип данных
  • диапазоны значений
  • структура GeoJSON
  • отсутствие NaN
  • корректный порядок [lng, lat]

Такая модель обработки снижает вероятность ошибок рендеринга и повышает устойчивость геоинформационных приложений.