UNPKG

@web-map-service/map2d-app

Version:

基于openlayer的2D地图应用

250 lines (220 loc) 6.57 kB
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 } }