В основе работы с удалёнными данными в OpenLayers лежит принцип
асинхронной подгрузки геопространственных ресурсов: векторных объектов,
тайлов, растровых слоёв и метаданных через HTTP-запросы. Библиотека не
навязывает единственный способ выполнения запросов, а предоставляет
уровень абстракции через загрузчики (loader), источники
данных (source) и форматтеры (format).
Основные сценарии AJAX-взаимодействия:
Ключевой точкой интеграции AJAX в OpenLayers является
ol/source/Vector. Источник поддерживает функцию
loader, которая вызывается при необходимости загрузки
данных.
import VectorSource from 'ol/source/Vector.js';
import VectorLayer from 'ol/layer/Vector.js';
import GeoJSON from 'ol/format/GeoJSON.js';
const vectorSource = new VectorSource({
loader: function () {
fetch('https://example.com/data/points.geojson')
.then(response => response.json())
.then(data => {
const features = new GeoJSON().readFeatures(data, {
featureProjection: 'EPSG:3857'
});
vectorSource.addFeatures(features);
})
.catch(error => console.error(error));
}
});
const vectorLayer = new VectorLayer({
source: vectorSource
});
В этом сценарии AJAX-запрос выполняется вручную через
fetch, а результат преобразуется в объекты
Feature.
Одним из ключевых механизмов динамической загрузки является использование ограничивающего прямоугольника (bounding box). При изменении области видимости карты выполняется запрос только нужных данных.
import VectorSource from 'ol/source/Vector.js';
import GeoJSON from 'ol/format/GeoJSON.js';
const vectorSource = new VectorSource({
loader: function (extent) {
const url = `https://example.com/api/features?bbox=${extent.join(',')}`;
fetch(url)
.then(res => res.json())
.then(data => {
const features = new GeoJSON().readFeatures(data, {
featureProjection: 'EPSG:3857'
});
vectorSource.addFeatures(features);
});
},
strategy: function (extent, resolution) {
return [extent];
}
});
extent передаётся автоматическиstrategy) определяет частоту вызовов
loaderПри частом панорамировании карты старые AJAX-запросы могут
становиться неактуальными. Для управления этим используется
AbortController.
let controller;
const vectorSource = new VectorSource({
loader: function (extent) {
if (controller) {
controller.abort();
}
controller = new AbortController();
const url = `https://example.com/api/data?bbox=${extent.join(',')}`;
fetch(url, { signal: controller.signal })
.then(res => res.json())
.then(data => {
vectorSource.clear();
const features = new GeoJSON().readFeatures(data, {
featureProjection: 'EPSG:3857'
});
vectorSource.addFeatures(features);
})
.catch(err => {
if (err.name !== 'AbortError') {
console.error(err);
}
});
}
});
Такой подход предотвращает накопление устаревших запросов и снижает нагрузку на сервер.
import TileLayer from 'ol/layer/Tile.js';
import XYZ from 'ol/source/XYZ.js';
const layer = new TileLayer({
source: new XYZ({
url: 'https://tile-server.com/{z}/{x}/{y}.png'
})
});
Каждый тайл — это отдельный AJAX-запрос, формируемый по шаблону URL.
import TileWMS from 'ol/source/TileWMS.js';
const layer = new TileLayer({
source: new TileWMS({
url: 'https://example.com/geoserver/wms',
params: {
LAYERS: 'workspace:layer',
TILED: true
}
})
});
WMS использует параметры запроса:
BBOXWIDTH / HEIGHTCRS или SRSimport GeoJSON from 'ol/format/GeoJSON.js';
const format = new GeoJSON();
const features = format.readFeatures(response, {
featureProjection: 'EPSG:3857'
});
import WFS from 'ol/format/WFS.js';
const format = new WFS();
const features = format.readFeatures(xmlResponse);
AJAX-ответы могут приходить как JSON, XML или текст, в зависимости от сервиса.
Пример построения запроса вручную:
const url = 'https://example.com/geoserver/wfs';
const params = new URLSearchParams({
service: 'WFS',
version: '2.0.0',
request: 'GetFeature',
typeName: 'workspace:layer',
outputFormat: 'application/json'
});
fetch(`${url}?${params.toString()}`)
.then(res => res.json())
.then(data => {
console.log(data);
});
OpenLayers позволяет полностью контролировать процесс загрузки.
const vectorSource = new VectorSource({
loader: function (extent, resolution, projection) {
const url = 'https://api.example.com/search';
const body = JSON.stringify({
bbox: extent,
srid: projection.getCode()
});
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: body
})
.then(res => res.json())
.then(data => {
const features = new GeoJSON().readFeatures(data, {
featureProjection: projection
});
vectorSource.addFeatures(features);
});
}
});
Такой подход используется при работе с:
fetch('https://api.example.com/data', {
headers: {
'Authorization': 'Bearer TOKEN_VALUE'
}
});
const url = `https://api.example.com/data?key=API_KEY`;
fetch(url)
.then(res => {
if (!res.ok) {
throw new Error('HTTP error');
}
return res.json();
})
.then(data => {
console.log(data);
})
.catch(err => {
console.error('Ошибка загрузки:', err);
});
Расширенные схемы включают:
const cache = new Map();
function load(url) {
if (cache.has(url)) {
return Promise.resolve(cache.get(url));
}
return fetch(url)
.then(res => res.json())
.then(data => {
cache.set(url, data);
return data;
});
}
Ключевые подходы:
При изменении:
выполняется пересчёт запросов через change-события:
map.getView().on('change:center', function () {
vectorSource.clear();
vectorSource.refresh();
});
AJAX-ответ часто приходит в EPSG:4326, тогда как карта работает в EPSG:3857.
import { fromLonLat } from 'ol/proj.js';
const feature = new Feature({
geometry: new Point(fromLonLat([longitude, latitude]))
});
При чтении GeoJSON:
new GeoJSON().readFeatures(data, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
});
Типичная цепочка обработки данных:
Эта модель обеспечивает гибкую интеграцию OpenLayers с любыми гео-сервисами и REST API, сохраняя контроль над каждым этапом сетевого взаимодействия.