OpenLayers 6: принудительный выбор многоугольника
Я реализовал OpenLayers 6 с взаимодействием Select и взаимодействием Draw, между которыми я переключаюсь.
Можно предположить, что пользователь рисует только многоугольники (геометрия из трех и более точек).
Я хочу, чтобы нарисованный многоугольник был выбран после его завершения.
Итак, я слушаю "drawend" во взаимодействии с рисованием, устанавливаю взаимодействие рисования как неактивное, устанавливаю взаимодействие выбора как активное, но затем мне нужно сделать выбранные элементы только рисованными.
Пока что у меня есть только этот неуклюжий прием, который я придумал:
// Find the center point of the drawn feature (EPSG:3857)
const featureCenter: [number, number] = this._getCenterOfExtent(geometry.getExtent());
// Get the local pixel coordinate for the feature's center
const pixel: Pixel = this._map.getPixelFromCoordinate(featureCenter);
// Create a new MapBrowserEvent registering a 'click' on this local pixel coordinate
const mbEvent: MapBrowserEvent = new MapBrowserEvent('click', this._map, new MouseEvent('click', {
bubbles: true,
cancelable: true,
clientX: pixel[0],
clientY: pixel[1]
}));
// Turn off multi-polygon selection on our Select Interaction. We only want the top polygon at this spot.
this._registeredSelector.setProperties({
multi: false
});
// Trigger the 'click' event on the map
this._map.dispatchEvent(mbEvent);
К сожалению, это не всегда работает. Я слушаю "щелчок" на моем взаимодействии "Выбрать", и он срабатывает после принудительного запуска щелчка. Однако иногда событие имеет несколько геометрических форм: Point, LineString и Polygon. Часто у него даже нет геометрии Polygon вselected
массив. В других случаях у него есть соседняя геометрия Многоугольника вselected
массив, а не тот, который мы нарисовали в последний раз.
Есть ли собственный метод OpenLayers для принудительного запуска выбора определенной функции?
Также вот мой _getCenterOfExtent
метод:
/* EXPECTS EPSG:3857 */
private _getCenterOfExtent(extent: Extent):[number, number] {
return [
extent[0] + (extent[2]-extent[0])/2,
extent[1] + (extent[3]-extent[1])/2
];
}
ОБНОВЛЕНИЕ Использование экранных координат для моего события щелчка по объекту окна, похоже, работает более точно, чем попытка клиентских координат по карте. Кроме того, я обнаружил, что программное переключениеmulti
на Select Interaction не работает, по крайней мере, не так, как я пытался. Я переключился на использование единственного выбора, что должно соответствовать нашим потребностям.
const bbox: ClientRect | DOMRect = this._map.getTargetElement().getBoundingClientRect();
let mbEvent: MapBrowserEvent | undefined;
if (bbox) {
pixel[0] += bbox.left;
pixel[1] += bbox.top;
mbEvent = new MapBrowserEvent('click', this._map, new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true,
screenX: pixel[0],
screenY: pixel[1]
}));
} else {
mbEvent = new MapBrowserEvent('click', this._map, new MouseEvent('click', {
bubbles: true,
cancelable: true,
clientX: pixel[0],
clientY: pixel[1]
}));
}
this._map.dispatchEvent(mbEvent);
1 ответ
Я нашел свой ответ в довольно малоизвестном месте. Это был старый ответ на старый вопрос о подгонке области просмотра к выбранному набору полигонов.
Похоже, что вы можете изменить коллекцию по ссылке, и карта обновится, чтобы отразить изменения.
Следовательно, мы можем получить Коллекцию выбранных функций из Взаимодействия Выбрать, очистить содержимое и установить новое содержимое.
import { Collection } from 'ol';
...
type RegisteredListener = (event: MapBrowserEvent | DrawEvent | SelectEvent) => boolean;
...
private _drawingSource: VectorSource = new VectorSource({wrapX: false});
private _drawingLayer: VectorLayer = new VectorLayer({
source: this._drawingSource
});
private _registeredDraw: Draw = new Draw({
source: this._drawingSource,
type: 'Polygon'
});
private _registeredSelector: Select = new Select({
condition: click,
multi: false,
filter: (feature: FeatureLike, layer: Layer) => {
const geometry: RenderFeature | Geometry | undefined = feature.getGeometry();
if (geometry && geometry.getType() === 'Polygon') {
return true;
}
return false;
}
});
...
private _onDrawEnd: RegisteredListener = (event: DrawEvent) => {
if (event.feature) {
// Get Collection of selected Features
const selectedCollection: Collection<FeatureLike> = this._registeredSelector.getFeatures();
// Clear the Collection
selectedCollection.clear();
// Add the recently drawn Feature to the collection
selectedCollection.push(event.feature);
event.stopPropagation();
// Re-enable the Select Interaction
// If we don't set a timeout before enabling the Select Interaction again,
// it will fire with the location if the last point, selecting only Point and/or LineString,
// not the Polygon. This would clear the selected features. This occurs even if we stop the event propagation.
setTimeout(() => {
this._registeredDraw.setActive(true);
this._registeredSelect.setActive(true);
});
}
return false;
}