@web-map-service/map2d-app
Version:
基于openlayer的2D地图应用
250 lines (220 loc) • 6.57 kB
text/typescript
import { App, Plugin } from '../types';
import { Element } from '../elements/types';
import { ElementSetDataItem, ElementEmitter } from '../elements';
import { util } from '../shared';
// 监听elements:created、elements:removed、elements:update 来对状态做处理
// 历史插件只对元素操作【新增、修改、删除】处理
type StateItem = {
element: Element
data?: ElementSetDataItem['data']
rawData?: ElementSetDataItem['data']
}
interface State {
type: 'add' | 'update' | 'remove';
data: StateItem[]
}
type ActionType = 'next' | 'back';
function addElements(app: App, state: State) {
const elements = state.data.map((item) => item.element)
app.element.add(elements);
}
function removeElements(app: App, state: State) {
const elements = state.data.map((item) => item.element)
app.element.remove(elements);
}
function updateElements(app: App, state: State, useRaw = false) {
// 如果是元素修改的话进行元素修改
// 应该要保留原始的数据
const elements: Element[] = []
for (const item of state.data) {
if (item.data?.data) {
// 数据更新
const rawData = item.rawData!.data!;
const data = item.data!.data!;
item.element.setData(!useRaw ? data : rawData);
}
if (item.data?.style) {
// 样式更新
const rawStyle = item.rawData!.style!;
const style = item.data.style;
item.element.setStyle(!useRaw ? style : rawStyle);
}
if (item.data?.name) {
// 名称更新
const rawName = item.rawData!.name!;
const name = item.data.name;
item.element.setName(!useRaw ? name : rawName);
}
if (item.data?.rotate) {
// 角度更新
const rawRotate = item.rawData!.rotate!;
const rotate = item.data.rotate;
item.element.setRotate(!useRaw ? rotate : rawRotate);
}
elements.push(item.element)
}
return elements;
}
function makeTool(app: App) {
let stateStack: State[] = [];
// 最大历史长度
const max = 50;
// 当前指针
let pointer = -1;
// 历史插件回溯进行中
let pending = false;
function pushState(state: State) {
// 如果状态栈的长度超限,则移除第一个栈元素,并栈尾追加一个新元素
if (stateStack.length >= max) {
stateStack.shift();
stateStack.push(state);
return;
}
stateStack = stateStack.slice(0, pointer + 1)
stateStack.push(state);
pointer++;
}
function useState(actionType: ActionType) {
// 启用当前的状态,前进是应用动作,后退是撤销动作
pending = true;
const state = stateStack[pointer];
if (
(actionType === 'next' && state.type === 'add') ||
(actionType === 'back' && state.type === 'remove')
) {
// 如果是前进操作,当前步骤是新增元素调用元素创建
// 如果是后退操作,当前步骤是移除元素,就新增该元素
addElements(app, state);
} else if (
(actionType === 'next' && state.type === 'remove') ||
(actionType === 'back' && state.type === 'add')
) {
// 如果是前进操作,当前步骤是移除元素调用元素移除
// 如果是后退操作,当前步骤是新增元素,就移除该元素
removeElements(app, state);
} else if (state.type === 'update') {
// 当前步骤是修改元素
// 如果是前进操作,则使用最新数据
// 如果是后退操作,则使用raw数据
if (actionType === 'next') {
updateElements(app, state, false);
} else {
updateElements(app, state, true);
}
}
app.emitter.emit('history', {
max,
pointer,
data: state.data,
type: state.type
});
pending = false;
}
function addedEmitter(elements: Element[]) {
if (pending) return;
const data = []
for (const element of elements) {
data.push({
element
})
}
const state: State = {
type: 'add',
data,
};
pushState(state);
}
function updateEmitter(elementSetDataItems: ElementSetDataItem[]) {
if (pending) return;
const data = []
for (const item of elementSetDataItems) {
data.push({
element: item.element,
rawData: {
data: util.deepCopy(item.element.data),
style: util.deepCopy(item.element.style),
name: util.deepCopy(item.element.name),
rotate: util.deepCopy(item.element.rotate),
},
data: item.data
})
}
const state: State = {
type: 'update',
data
};
pushState(state);
}
function removeEmitter(elements: Element[]) {
if (pending) return;
const data = []
for (const element of elements) {
data.push({
element
})
}
const state: State = {
type: 'remove',
data,
};
pushState(state);
}
const tool = {
enabled: false,
enable() {
if (tool.enabled) return;
// 监听元素创建上图
app.emitter.on(ElementEmitter.add, addedEmitter);
// 监听元素移除
app.emitter.on(ElementEmitter.remove, removeEmitter);
// 监听元素修改
app.emitter.on(ElementEmitter.update, updateEmitter);
tool.enabled = true;
},
close() {
if (!tool.enabled) return;
app.emitter.remove(ElementEmitter.add, addedEmitter);
app.emitter.remove(ElementEmitter.remove, removeEmitter);
app.emitter.remove(ElementEmitter.update, updateEmitter);
tool.enabled = false;
},
next() {
// 指针不能大于状态的长度
if (pointer === stateStack.length - 1) return;
pointer++;
useState('next');
},
back() {
// 指针-1时直接跳出
if (pointer === -1) return;
useState('back');
pointer--;
},
clean() {
stateStack = [];
},
};
return tool;
}
export function createPlugin() {
let app: App;
const plugin: Plugin = {
type: 'history',
install(_app: App) {
app = _app;
app.tools.history = makeTool(app);
return app;
},
};
return plugin;
}
declare module './tool' {
interface Tools {
history: ReturnType<typeof makeTool>;
}
}
declare module '../types' {
interface AppEmitterEvent {
history: any
}
}