需要用OpenLayers实现视图切换,即在某一视图下,可以保存当前的视图状态,经过平移/缩放等改变视图的操作之后,通过点击按钮等交互动作可以回到上一视图,并且能够按顺序在保存的视图之间按顺序逐个切换。
难点的交互部分用了一个现成的轮子:ol-ext
ol-ext提供了一个扩展的interaction类:ol.interaction.UndoRedo,它维护了一个状态队列和位置指针,可以通过API实现对队列中的状态进行访问,并通过自定义的undo、redo函数实现操作的撤销跟回滚。
另外我还用了一个ol-ext中的按钮控件,用作界面交互操作(用法略)。
UndoRedo组件跟ol原生的其他组件用法类似:
var undoInteraction = new ol.interaction.UndoRedo();
map.addInteraction(undoInteraction);
然后向地图上添加按钮控件:
var bar = new ol.control.Bar({
group: true,
controls: [
new ol.control.Button({
html: '',
title: '上一视图',
handleClick: function () {
undoInteraction.undo();
}
}),
new ol.control.Button({
html: '',
title: '下一视图',
handleClick: function () {
undoInteraction.redo();
}
}),
new ol.control.Button({
html: '',
title: '保存当前视图',
handleClick: function () {
saveExtent();
}
}),
]
});
mainbar.addControl(bar);
undoInteraction.undo()和 undoInteraction.redo()就是UndoRedo组件实现“上一步”“下一步”的API。按钮控件就很简单了,略过不谈。
接下来核心部分是逻辑处理:
var extent = map.getView().calculateExtent(map.getSize());
undoInteraction.define(
'extent',
function (s) {
extent = s.before;
map.getView().fit(extent, {
nearest: true,
duration: 1000,
easing: ol.easing.easeOut
});
},
function (s) {
extent = s.after;
map.getView().fit(extent, {
nearest: true,
duration: 1000,
easing: ol.easing.easeOut
});
}
);
function saveExtent() {
var before = extent.slice();
extent = map.getView().calculateExtent(map.getSize())
// use blockStart / blockEnd to stack many undo in a same action
// undoInteraction.blockStart();
// Add undo style action
if(!ol.extent.equals(before, extent))
undoInteraction.push("extent", {
before: before,
after: extent
});
// undoInteraction.blockEnd();
}
saveExtent();
ol.interaction.UndoRedo的“驱动”部分是这样一个结构:
ol.interaction.UndoRedo.define("key", function undo(s), function redo(s))
需要保存状态的时候,要调用:
ol.interaction.UndoRedo.push("key",{
before:
after:
})
传入undo和redo的参数s是一个状态指针,包含了相对当前状态的前一状态和后一状态;
保存当前状态的saveExtent()中,要做的事情是将变化前的extent保存给before,当前状态保存为after。
逻辑还是比较简单的。
ol-ext: Undo/redo
我在企鹅家的课堂和CSDN学院都开通了《OpenLayers实例详解》课程,欢迎报名学习。搜索关键字OpenLayers就能看到。