interaction
OpenLayers中表達交互功能的基類是interaction
,它是一個虛基類,不負責實例化,交互功能都繼承該基類,實現它的子類包括:
- DoubleClickZoom 雙擊放大交互功能;
- DragAndDrop 以“拖文件到地圖中”的交互添加圖層;
- DragBox 拉框,用於劃定一個矩形範圍,常用於放大地圖;
- DragPan 拖拽平移地圖;
- DragRotate 拖拽方式旋轉地圖;
- DragRotateAndZoom 拖拽方式進行縮放和旋轉地圖;
- DragZoom 拖拽方式縮放地圖;
- Draw 繪製地理要素功能;
- Extent 單擊並拖動地圖來繪製矢量框,並可編輯
- KeyboardPan 鍵盤方式平移地圖;
- KeyboardZoom 鍵盤方式縮放地圖;
- Modify 更改要素;
- MouseWheelZoom 鼠標滾輪縮放功能;
- PinchRotate 手指旋轉地圖,針對觸摸屏;
- PinchZoom 手指進行縮放,針對觸摸屏;
- Pointer 鼠標的用戶自定義事件基類;
- Select 選擇要素功能;
- Snap 鼠標捕捉,當鼠標距離某個要素一定距離之內,自動吸附到要素。
- Translate 拖拽移動選中的要素(新增)
用法
// 先實例化
var select = new Select();
var translate = new Translate({
features: select.getFeatures(),
});
// 可以初始化時添加
var map = new Map({
interactions: defaultInteractions().extend([select, translate]),
layers: [raster, vector],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2,
}),
});
// 也可以後續追加
map.addInteraction(select );
map.addInteraction(translate );
默認交互
地圖初始化時,如果沒有設置交互類型,就會默認綁定一些預設的交互,包括:
- DragRotate 拖拽旋轉
- DoubleClickZoom 雙擊放大
- DragPan 拖拽平移
- PinchRotate 手指旋轉
- PinchZoom 手指縮放
- KeyboardPan 鍵盤平移
- KeyboardZoom 鍵盤縮放
- MouseWheelZoom 滾輪縮放
- DragZoom 拖拽縮放
事件機制解析
看下ol的事件綁定和觸發,入口 Map.js
function Map(options) {
// ...
if (!options.interactions) {
options.interactions = defaultInteractions({ // 沒有指定就加載默認交互
onFocusOnly: true,
});
}
// ...
}
Map的父類 PluggableMap.js
// 構造函數
function PluggableMap(options) {
var _this = _super.call(this) || this;
var optionsInternal = createOptionsInternal(options); // 屬性初始化
_this.viewport_ = document.createElement('div'); // 地圖容器內的主div
// 監聽各屬性更新事件
_this.addEventListener(getChangeEventType(MapProperty.LAYERGROUP), _this.handleLayerGroupChanged_);
_this.addEventListener(getChangeEventType(MapProperty.VIEW), _this.handleViewChanged_);
_this.addEventListener(getChangeEventType(MapProperty.SIZE), _this.handleSizeChanged_);
_this.addEventListener(getChangeEventType(MapProperty.TARGET), _this.handleTargetChanged_);
// 通過setProperties更新屬性,觸發上面監聽事件
// 這個方法
_this.setProperties(optionsInternal.values);
}
// 地圖容器更新觸發的方法
PluggableMap.prototype.handleTargetChanged_ = function () {
var targetElement = this.getTargetElement(); // 獲取到地圖容器
targetElement.appendChild(this.viewport_);
// 實例化一個瀏覽器事件處理類
this.mapBrowserEventHandler_ = new MapBrowserEventHandler(this, this.moveTolerance_);
for (var key in MapBrowserEventType) {
// 循環所有支持的瀏覽器事件類型,逐一綁定,觸發方法內循環遍歷綁定的interaction
this.mapBrowserEventHandler_.addEventListener(MapBrowserEventType[key], this.handleMapBrowserEvent.bind(this));
}
// 綁定右擊事件
this.viewport_.addEventListener(EventType.CONTEXTMENU, this.boundHandleBrowserEvent_, false);
// 綁定滾輪事件
this.viewport_.addEventListener(EventType.WHEEL, this.boundHandleBrowserEvent_, PASSIVE_EVENT_LISTENERS ? { passive: false } : false);
// 綁定鍵盤事件
this.keyHandlerKeys_ = [
listen(keyboardEventTarget, EventType.KEYDOWN, this.handleBrowserEvent, this),
listen(keyboardEventTarget, EventType.KEYPRESS, this.handleBrowserEvent, this),
];
// 綁定resize事件
if (!this.handleResize_) {
this.handleResize_ = this.updateSize.bind(this);
window.addEventListener(EventType.RESIZE, this.handleResize_, false);
}
}
// 各交互事件觸發的方法
PluggableMap.prototype.handleMapBrowserEvent = function (mapBrowserEvent) {
var interactionsArray = this.getInteractions().getArray(); // 取出所有綁定的 Interactions
if (this.dispatchEvent(mapBrowserEvent) !== false) {
for (var i = interactionsArray.length - 1; i >= 0; i--) {
var interaction = interactionsArray[i];
if (!interaction.getActive()) { //判斷是否處於激活狀態
continue;
}
//調用執行各Interactions子類的處理方法
var cont = interaction.handleEvent(mapBrowserEvent);
if (!cont) {
break;
}
}
}
}
Interactions
的子類DoubleClickZoom
爲例,看事件響應部分
DoubleClickZoom.prototype.handleEvent = function (mapBrowserEvent) {
var stopEvent = false;
// 判斷下是否觸發的是自己,再響應
if (mapBrowserEvent.type == MapBrowserEventType.DBLCLICK) {
var browserEvent = (mapBrowserEvent.originalEvent);
var map = mapBrowserEvent.map;
var anchor = mapBrowserEvent.coordinate;
var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;
var view = map.getView();
zoomByDelta(view, delta, anchor, this.duration_);
mapBrowserEvent.preventDefault();
stopEvent = true;
}
return !stopEvent;
};
可以看到 ol 的事件基本都是在viewport
和target
上綁着,並沒有直接綁定在canvas上