Translate для перемещения

Интерактивное перемещение объектов на карте в OpenLayers реализуется через взаимодействие Translate, предназначенное для перетаскивания геометрий по поверхности карты без изменения их формы. В отличие от редактирования вершин, Translate работает с целыми объектами, изменяя их координаты единым смещением, что делает его основным инструментом для drag-and-drop сценариев в картографических приложениях.

Translate взаимодействует с векторными объектами (features) и изменяет их геометрию на основе вычисленного смещения между начальной и текущей позицией курсора. При захвате объекта фиксируется исходная точка, далее каждое движение мыши преобразуется в вектор смещения в системе координат карты.

Ключевая особенность заключается в том, что Translate не модифицирует структуру геометрии (например, количество вершин), а применяет трансформацию ко всей геометрии целиком. Это делает его предсказуемым и эффективным для перемещения сложных объектов.

Подключение и базовая инициализация

В OpenLayers Translate реализован как взаимодействие ol/interaction/Translate. Подключение выполняется через создание экземпляра и добавление его в карту.

import Map from 'ol/Map.js';
import View from 'ol/View.js';
import Translate from 'ol/interaction/Translate.js';
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';

const source = new VectorSource();

const layer = new VectorLayer({
  source: source
});

const translate = new Translate({
  features: source.getFeaturesCollection()
});

const map = new Map({
  target: 'map',
  layers: [layer],
  view: new View({
    center: [0, 0],
    zoom: 2
  }),
  interactions: [
    translate
  ]
});

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

Основные параметры Translate

Translate принимает объект настроек, определяющий поведение взаимодействия.

features

Позволяет задать набор объектов, которые можно перемещать. Это может быть Collection или массив features.

new Translate({
  features: selectedFeatures
});

Использование коллекции удобно при реализации выделения объектов.

layers

Альтернативный способ ограничения области перемещения — указание слоёв.

new Translate({
  layers: [vectorLayer]
});

В этом случае перемещаться будут все объекты указанных слоёв.

filter

Функция фильтрации позволяет более точно контролировать, какие объекты могут быть перемещены.

new Translate({
  filter: function(feature, layer) {
    return feature.get('draggable') === true;
  }
});

Фильтр выполняется при каждом попытке захвата объекта.

condition

Позволяет задать условие активации взаимодействия (например, только при нажатой клавише Shift).

import { shiftKeyOnly } from 'ol/events/condition.js';

new Translate({
  condition: shiftKeyOnly
});

Это полезно при комбинировании нескольких типов взаимодействий.

События Translate

Translate генерирует набор событий, позволяющих отслеживать процесс перемещения.

translatestart

Срабатывает в момент начала перемещения.

translate.on('translatestart', function(event) {
  const features = event.features;
  console.log('Начато перемещение:', features.getLength());
});

На этом этапе можно сохранять исходные координаты или состояние объектов.

translating

Событие вызывается во время перемещения, при каждом изменении позиции.

translate.on('translating', function(event) {
  const delta = event.delta;
  console.log('Смещение:', delta);
});

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

translateend

Срабатывает после завершения перемещения.

translate.on('translateend', function(event) {
  const features = event.features;
  console.log('Перемещение завершено');
});

На этом этапе обычно выполняется сохранение изменений в источник данных или отправка на сервер.

Работа с выделенными объектами

На практике Translate часто используется совместно с механизмом выделения (Select). Это позволяет перемещать только выбранные пользователем объекты.

import Sel ect from 'ol/interaction/Select.js';

const select = new Select();

const translate = new Translate({
  features: select.getFeatures()
});

map.addInteraction(select);
map.addInteraction(translate);

Такой подход разделяет логику выбора и перемещения, делая интерфейс более гибким.

Геометрические особенности перемещения

Translate работает с любыми типами геометрий:

  • Point
  • LineString
  • Polygon
  • MultiPoint
  • MultiPolygon

Все координаты геометрии смещаются одинаково, что гарантирует сохранение формы.

При перемещении Polygon, например, изменяются все вершины контура одновременно, включая внутренние кольца (holes).

Особенности работы в разных проекциях

OpenLayers использует проекцию карты (обычно Web Mercator EPSG:3857). Translate выполняет преобразования в координатах карты, а не в экранных пикселях.

Это означает:

  • перемещение не зависит от масштаба
  • одинаковое движение курсора даёт одинаковое географическое смещение
  • корректно работает при любом зуме

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

Ограничение области перемещения

В реальных приложениях часто требуется ограничить перемещение объектов определённой областью.

Ограничение через проверку координат

translate.on('translating', function(event) {
  const geometry = event.features.item(0).getGeometry();
  const extent = geometry.getExtent();

  if (extent[0] < -1000000) {
    event.preventDefault();
  }
});

Ограничение через бизнес-логику

Более корректный подход — откатывать изменения после translateend, если объект вышел за допустимые границы.

Визуальная обратная связь

При перемещении объектов часто требуется изменить их стиль для улучшения UX.

translate.on('translatestart', function(event) {
  event.features.forEach(function(feature) {
    feature.setStyle(highlightStyle);
  });
});

translate.on('translateend', function(event) {
  event.features.forEach(function(feature) {
    feature.setStyle(defaultStyle);
  });
});

Это помогает пользователю понять, какие объекты находятся в активном состоянии.

Совмещение с Modify

Translate и Modify взаимодействия решают разные задачи:

  • Translate — перемещение целиком
  • Modify — изменение формы

Их можно использовать одновременно:

import Modify fr om 'ol/interaction/Modify.js';

map.addInteraction(new Modify({ source: source }));
map.addInteraction(new Translate({ features: sel ect.getFeatures() }));

Важно учитывать порядок взаимодействий, чтобы избежать конфликтов при обработке событий мыши.

Производительность при большом количестве объектов

При работе с большим количеством features Translate может сталкиваться с нагрузкой из-за постоянного пересчёта геометрий.

Рекомендации:

  • использовать Collection только для выбранных объектов
  • избегать глобального Translate на всех слоях сразу
  • минимизировать количество фильтраций в filter
  • не выполнять тяжёлые операции в translating

Drag-and-drop сценарии

Translate часто применяется для:

  • перемещения маркеров на карте
  • редактирования точек интереса (POI)
  • перестановки объектов логистики
  • интерактивного планирования зон

Пример добавления нового маркера и его перемещения:

const feature = new Feature({
  geometry: new Point([0, 0])
});

source.addFeature(feature);

const select = new Select({
  condition: singleClick
});

const translate = new Translate({
  features: select.getFeatures()
});

map.addInteraction(select);
map.addInteraction(translate);

Контроль точности перемещения

При необходимости можно «привязывать» перемещение к шагу сетки:

translate.on('translating', function(event) {
  event.features.forEach(function(feature) {
    const geom = feature.getGeometry();
    const coord = geom.getCoordinates();

    const snapped = [
      Math.round(coord[0] / 1000) * 1000,
      Math.round(coord[1] / 1000) * 1000
    ];

    geom.setCoordinates(snapped);
  });
});

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

Поведение при множественном выборе

Translate поддерживает перемещение нескольких объектов одновременно. В этом случае смещение применяется ко всей группе, сохраняя взаимное расположение.

select.getFeatures().push(feature1);
select.getFeatures().push(feature2);

При захвате одного из объектов перемещается вся коллекция.

Взаимодействие с событиями карты

Translate может конфликтовать с базовыми событиями карты, такими как drag-pan. Обычно это решается настройкой условий активации:

import { platformModifierKeyOnly } fr om 'ol/events/condition.js';

new Translate({
  condition: platformModifierKeyOnly
});

Это позволяет избежать случайного перемещения при навигации по карте.

Хранение изменений

После завершения перемещения данные обычно синхронизируются с источником:

translate.on('translateend', function(event) {
  const feature = event.features.item(0);
  const geometry = feature.getGeometry();

  const coords = geometry.getCoordinates();

  fetch('/api/save', {
    method: 'POST',
    body: JSON.stringify({ coords })
  });
});

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