Загрузка данных из URL

Одной из ключевых возможностей Kepler.gl является работа с удалёнными источниками данных. Вместо хранения файлов непосредственно в приложении данные могут загружаться по URL-адресу с веб-серверов, API, облачных хранилищ или CDN. Такой подход особенно полезен при работе с большими наборами геоданных, динамически обновляемой информацией и распределёнными архитектурами.

Загрузка данных из URL позволяет:

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

Принцип работы загрузки данных

В типичном сценарии приложение выполняет следующие действия:

  1. Получает URL удалённого ресурса.
  2. Выполняет HTTP-запрос.
  3. Загружает содержимое файла.
  4. Преобразует данные в формат, понятный Kepler.gl.
  5. Передаёт данные в хранилище Redux через соответствующие действия.

Схема процесса:

URL
 ↓
HTTP-запрос
 ↓
Получение данных
 ↓
Парсинг
 ↓
addDataToMap()
 ↓
Отображение на карте

Поддерживаемые форматы данных

Kepler.gl способен работать с различными типами геопространственных данных:

Формат Назначение
CSV Табличные данные
JSON Универсальный формат обмена
GeoJSON Географические объекты
KML Геоданные Google Earth
Shapefile Классический GIS-формат
GPX GPS-треки и маршруты

При загрузке через URL наиболее часто используются CSV и GeoJSON.


Загрузка CSV-файла по URL

Предположим, имеется удалённый файл:

https://example.com/data/cities.csv

Содержимое:

city,lat,lng,population
Almaty,43.238949,76.889709,2000000
Astana,51.169392,71.449074,1400000
Shymkent,42.341685,69.590101,1100000

Получение данных осуществляется через Fetch API:

fetch('https://example.com/data/cities.csv')
  .then(response => response.text())
  .then(data => {
    console.log(data);
  });

После получения содержимое файла представляет собой обычную строку.


Использование processCsvData

Kepler.gl содержит набор утилит для обработки данных.

Импорт:

import {processCsvData} from '@kepler.gl/processors';

Загрузка и обработка:

fetch('https://example.com/data/cities.csv')
  .then(response => response.text())
  .then(csv => {
    const dataset = processCsvData(csv);

    dispatch(
      addDataToMap({
        datasets: dataset
      })
    );
  });

После выполнения данные автоматически появляются на карте.


Загрузка GeoJSON по URL

GeoJSON является одним из наиболее распространённых форматов пространственных данных.

Пример URL:

https://example.com/data/regions.geojson

Получение данных:

fetch('https://example.com/data/regions.geojson')
  .then(response => response.json())
  .then(data => {
    console.log(data);
  });

Структура GeoJSON:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [76.889709, 43.238949]
      },
      "properties": {
        "name": "Almaty"
      }
    }
  ]
}

Обработка GeoJSON

Для преобразования используется специальный процессор.

import {processGeojson} from '@kepler.gl/processors';

Пример:

fetch('https://example.com/data/regions.geojson')
  .then(response => response.json())
  .then(json => {
    const dataset = processGeojson(json);

    dispatch(
      addDataToMap({
        datasets: dataset
      })
    );
  });

Kepler.gl автоматически определяет типы геометрий:

  • Point;
  • MultiPoint;
  • LineString;
  • MultiLineString;
  • Polygon;
  • MultiPolygon.

Использование async/await

Современный подход предполагает использование асинхронных функций.

async function loadData() {
  const response = await fetch(
    'https://example.com/data/cities.csv'
  );

  const csv = await response.text();

  const dataset = processCsvData(csv);

  dispatch(
    addDataToMap({
      datasets: dataset
    })
  );
}

Вызов:

loadData();

Код становится более читаемым по сравнению с цепочками .then().


Загрузка нескольких файлов

Часто требуется отображать сразу несколько наборов данных.

Например:

cities.csv
roads.geojson
regions.geojson

Загрузка выполняется параллельно:

const [
  citiesResponse,
  roadsResponse,
  regionsResponse
] = await Promise.all([
  fetch('/data/cities.csv'),
  fetch('/data/roads.geojson'),
  fetch('/data/regions.geojson')
]);

Получение содержимого:

const cities = await citiesResponse.text();
const roads = await roadsResponse.json();
const regions = await regionsResponse.json();

Преобразование:

const cityDataset = processCsvData(cities);
const roadDataset = processGeojson(roads);
const regionDataset = processGeojson(regions);

Передача в карту:

dispatch(
  addDataToMap({
    datasets: [
      cityDataset,
      roadDataset,
      regionDataset
    ]
  })
);

Добавление идентификаторов наборов данных

Для корректного управления слоями рекомендуется задавать идентификаторы.

const dataset = {
  info: {
    id: 'cities',
    label: 'Cities'
  },
  data: processCsvData(csv).data
};

Добавление:

dispatch(
  addDataToMap({
    datasets: dataset
  })
);

Преимущества:

  • удобное управление слоями;
  • возможность обновления конкретного набора;
  • понятные названия в интерфейсе.

Работа с удалённым API

Источник данных необязательно должен быть файлом.

Возможна загрузка из REST API.

Пример ответа сервера:

[
  {
    "name": "Almaty",
    "lat": 43.238949,
    "lng": 76.889709
  },
  {
    "name": "Astana",
    "lat": 51.169392,
    "lng": 71.449074
  }
]

Получение данных:

const response = await fetch(
  'https://api.example.com/cities'
);

const data = await response.json();

Подготовка API-данных для Kepler.gl

Не все API возвращают данные в формате, который может напрямую использоваться картой.

Преобразование:

const rows = data.map(city => ({
  name: city.name,
  latitude: city.lat,
  longitude: city.lng
}));

Создание структуры таблицы:

const dataset = {
  fields: [
    {name: 'name'},
    {name: 'latitude'},
    {name: 'longitude'}
  ],
  rows: rows.map(item => [
    item.name,
    item.latitude,
    item.longitude
  ])
};

После этого данные можно передать в карту.


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

Иногда набор данных регулярно изменяется.

Пример обновления каждые 30 секунд:

setInterval(async () => {
  const response = await fetch(
    '/data/vehicles.geojson'
  );

  const geojson = await response.json();

  const dataset = processGeojson(geojson);

  dispatch(
    addDataToMap({
      datasets: dataset
    })
  );
}, 30000);

Такой механизм часто используется для:

  • транспорта;
  • телеметрии;
  • мониторинга объектов;
  • IoT-систем;
  • логистики.

Обработка ошибок загрузки

Удалённый сервер может быть недоступен.

Поэтому необходимо контролировать ошибки.

try {
  const response = await fetch(url);

  if (!response.ok) {
    throw new Error(
      `HTTP Error: ${response.status}`
    );
  }

  const data = await response.json();

  console.log(data);
}
catch (error) {
  console.error(error);
}

Типичные проблемы:

  • ошибка DNS;
  • отсутствие интернет-соединения;
  • неверный URL;
  • ошибка сервера;
  • тайм-аут запроса.

Проверка статуса ответа

Перед обработкой рекомендуется проверять статус.

const response = await fetch(url);

if (response.status === 404) {
  console.log('Файл не найден');
}

if (response.status === 500) {
  console.log('Ошибка сервера');
}

Наиболее распространённые коды:

Код Значение
200 Успешно
201 Создано
301 Перенаправление
403 Доступ запрещён
404 Не найдено
500 Ошибка сервера

Работа с CORS

При загрузке данных с другого домена часто возникает ошибка:

Access to fetch at ...
has been blocked by CORS policy

Причина заключается в ограничениях браузера.

Сервер должен отправлять заголовок:

Access-Control-Allow-Origin: *

Либо:

Access-Control-Allow-Origin: https://myapp.com

Без корректной настройки CORS браузер блокирует запрос ещё до получения данных.


Использование параметров запроса

URL может содержать параметры фильтрации.

Пример:

const url =
  'https://api.example.com/events?year=2025';

Формирование параметров через URLSearchParams:

const params = new URLSearchParams({
  year: 2025,
  country: 'Kazakhstan'
});

const response = await fetch(
  `https://api.example.com/events?${params}`
);

Такой подход упрощает построение динамических запросов.


Передача заголовков

Некоторые API требуют авторизацию.

const response = await fetch(url, {
  headers: {
    Authorization: 'Bearer TOKEN'
  }
});

Дополнительные заголовки:

headers: {
  Authorization: 'Bearer TOKEN',
  Accept: 'application/json',
  'Content-Type': 'application/json'
}

Индикатор загрузки

При работе с большими файлами желательно отображать состояние загрузки.

Пример:

setLoading(true);

try {
  const response = await fetch(url);

  const json = await response.json();

  const dataset = processGeojson(json);

  dispatch(
    addDataToMap({
      datasets: dataset
    })
  );
}
finally {
  setLoading(false);
}

Типичный интерфейс:

{
  loading && (
    <div>
      Loading...
    </div>
  )
}

Кэширование данных

Для уменьшения нагрузки на сервер можно сохранять результаты запросов.

Простейший вариант:

const cache = new Map();

Проверка:

if (cache.has(url)) {
  return cache.get(url);
}

Сохранение:

cache.set(url, data);

Преимущества:

  • меньше сетевых запросов;
  • более быстрое отображение;
  • снижение нагрузки на инфраструктуру.

Загрузка данных при инициализации карты

Наиболее распространённый сценарий в React-приложениях выглядит следующим образом:

useEffect(() => {
  async function load() {
    const response = await fetch(
      '/data/cities.geojson'
    );

    const geojson =
      await response.json();

    const dataset =
      processGeojson(geojson);

    dispatch(
      addDataToMap({
        datasets: dataset
      })
    );
  }

  load();
}, []);

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


Оптимизация загрузки больших наборов данных

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

  • использовать сжатие GZIP или Brotli;
  • загружать только необходимые поля;
  • применять пагинацию на сервере;
  • выполнять предварительную фильтрацию;
  • использовать GeoJSON только при необходимости хранения геометрии;
  • разделять данные на тематические наборы;
  • использовать CDN для статических файлов;
  • минимизировать объём передаваемых атрибутов.

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