Измерение расстояний — одна из наиболее востребованных функций геоинформационных приложений. Пользователь может определять длину маршрутов, расстояние между объектами, размеры участков местности, протяжённость инженерных коммуникаций и другие пространственные характеристики.
В OpenLayers измерение расстояний обычно реализуется с помощью:
LineString;Draw;Подход основан на том, что пользователь рисует линию на карте, а приложение в режиме реального времени вычисляет её длину.
Для измерений потребуется стандартная карта и векторный слой, в котором будут храниться создаваемые линии.
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import OSM from 'ol/source/OSM.js';
const vectorSource = new VectorSource();
const vectorLayer = new VectorLayer({
source: vectorSource
});
const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
}),
vectorLayer
],
view: new View({
center: [0, 0],
zoom: 2
})
});
После создания карты необходимо добавить инструмент рисования линий.
Взаимодействие Draw позволяет пользователю создавать
новые геометрические объекты непосредственно на карте.
import Draw from 'ol/interaction/Draw.js';
const draw = new Draw({
source: vectorSource,
type: 'LineString'
});
map.addInteraction(draw);
Параметр:
| Параметр | Описание |
|---|---|
source |
Источник, куда сохраняются объекты |
type |
Тип создаваемой геометрии |
В данном случае используется LineString, поскольку
расстояние измеряется по линии.
После завершения рисования можно получить объект и вычислить его длину.
draw.on('drawend', function(event) {
const feature = event.feature;
const geometry = feature.getGeometry();
const length = geometry.getLength();
console.log(length);
});
Метод:
geometry.getLength()
возвращает длину линии в единицах используемой проекции.
Важно понимать, что метод getLength() работает в
координатах текущей проекции.
Если используется проекция Web Mercator (EPSG:3857),
результат представляет собой приблизительное значение в метрах и может
содержать погрешности, особенно на больших расстояниях и в высоких
широтах.
Пример:
const length = geometry.getLength();
console.log(`${length} м`);
Такой подход подходит для простых задач, однако для точных геодезических измерений рекомендуется использовать сферические вычисления.
OpenLayers содержит модуль сферических вычислений.
import {getLength} from 'ol/sphere.js';
Использование:
const length = getLength(geometry);
console.log(length);
Теперь расчёт выполняется по поверхности Земли с учётом её кривизны.
Это существенно повышает точность измерений.
geometry.getLength();
Особенности:
getLength(geometry);
Особенности:
На практике большинство приложений используют именно сферический расчёт.
Для удобства отображения длина обычно переводится в километры при больших значениях.
Пример функции форматирования:
function formatLength(length) {
if (length > 1000) {
return (length / 1000).toFixed(2) + ' км';
}
return length.toFixed(2) + ' м';
}
Использование:
const length = getLength(geometry);
console.log(formatLength(length));
Примеры результатов:
| Значение | Вывод |
|---|---|
| 120 | 120.00 м |
| 850 | 850.00 м |
| 1450 | 1.45 км |
| 23500 | 23.50 км |
Наиболее удобный вариант — показывать расстояние непосредственно во время рисования линии.
Для этого отслеживается изменение геометрии.
draw.on('drawstart', function(event) {
const feature = event.feature;
feature.getGeometry().on('change', function(evt) {
const geometry = evt.target;
const length = getLength(geometry);
console.log(formatLength(length));
});
});
Каждый раз при добавлении новой вершины будет вычисляться новая длина.
Вывод измерения в консоль подходит только для отладки. В реальных приложениях результат отображается на карте.
Создание HTML-элемента:
<div id="measureTooltip"></div>
Создание Overlay:
import Overlay from 'ol/Overlay.js';
const tooltipElement =
document.getElementById('measureTooltip');
const tooltip = new Overlay({
element: tooltipElement,
offset: [0, -15],
positioning: 'bottom-center'
});
map.addOverlay(tooltip);
Во время рисования подсказка может следовать за последней точкой линии.
feature.getGeometry().on('change', function(evt) {
const geometry = evt.target;
const coordinates =
geometry.getLastCoordinate();
const length = getLength(geometry);
tooltipElement.innerHTML =
formatLength(length);
tooltip.setPosition(coordinates);
});
Теперь пользователь видит текущую длину рядом с курсором.
Пример CSS-оформления:
#measureTooltip {
background: rgba(0,0,0,0.7);
color: white;
padding: 4px 8px;
border-radius: 4px;
white-space: nowrap;
font-size: 12px;
}
Такой стиль напоминает измерительные инструменты профессиональных ГИС-систем.
Для повышения читаемости можно использовать собственный стиль.
import Style from 'ol/style/Style.js';
import Stroke from 'ol/style/Stroke.js';
vectorLayer.setStyle(
new Style({
stroke: new Stroke({
color: '#ff0000',
width: 3
})
})
);
Результат:
Часто требуется показывать точки маршрута.
import CircleStyle from 'ol/style/Circle.js';
import Fill from 'ol/style/Fill.js';
const style = new Style({
stroke: new Stroke({
color: '#ff0000',
width: 3
}),
image: new CircleStyle({
radius: 5,
fill: new Fill({
color: '#ffffff'
}),
stroke: new Stroke({
color: '#ff0000',
width: 2
})
})
});
Вершины позволяют лучше контролировать процесс измерения.
Иногда требуется хранить только одно измерение.
Перед началом нового измерения можно очищать источник:
draw.on('drawstart', function() {
vectorSource.clear();
});
На карте всегда будет отображаться только последняя линия.
Полная очистка выполняется следующим образом:
vectorSource.clear();
Либо через кнопку интерфейса:
document
.getElementById('clear')
.addEventListener('click', () => {
vectorSource.clear();
});
Линия может содержать любое количество сегментов.
A ---- B
\
C
\
D
Общая длина определяется как сумма длин всех сегментов:
AB + BC + CD
Пользователь может строить маршруты произвольной формы, а OpenLayers автоматически вычисляет их суммарную длину.
Координаты линии доступны через метод:
const coordinates =
geometry.getCoordinates();
Пример:
[
[x1, y1],
[x2, y2],
[x3, y3]
]
Каждая пара соседних точек образует отдельный сегмент.
При необходимости длина каждого сегмента может вычисляться отдельно.
Для профессиональных измерительных инструментов полезно подписывать каждый участок маршрута.
Алгоритм:
Подобный подход используется в кадастровых и инженерных ГИС.
Полный пример расчёта после завершения рисования:
import {getLength} from 'ol/sphere.js';
draw.on('drawend', function(event) {
const geometry =
event.feature.getGeometry();
const length =
getLength(geometry);
alert(
'Расстояние: ' +
formatLength(length)
);
});
После завершения построения маршрута пользователь получает итоговую длину.
Полноценный инструмент измерения расстояний обычно состоит из следующих компонентов:
ol/sphere.Такая структура применяется в большинстве веб-ГИС, построенных на OpenLayers.
Для максимальной точности
Использовать:
import {getLength} from 'ol/sphere.js';
вместо:
geometry.getLength();
Для удобства пользователей
Показывать длину в режиме реального времени во время рисования.
Для крупных проектов
Отдельно реализовывать:
Для профессиональных ГИС
Комбинировать:
Такой подход позволяет создавать полноценные измерительные инструменты, сопоставимые по возможностям с настольными геоинформационными системами.