openlayers撤销与恢复

分享一个openlayers编辑要素节点,并且支持撤销与恢复的小demo:

javascript 复制代码
    const baseMap = new ol.layer.Tile({
      source: new ol.source.OSM(),
    });

    const feature = new ol.Feature({
      geometry: new ol.geom.Polygon([[
        [-1000000, 5000000],
        [-1000000, 2500000],
        [0, 2500000],
        [0, 5000000],
        [-1000000, 5000000],
      ]])
    });

    const vectorSource = new ol.source.Vector({
      features: [feature]
    });

    const vectorLayer = new ol.layer.Vector({
      source: vectorSource,
      style: new ol.style.Style({
        stroke: new ol.style.Stroke({
          color: '#ffcc33',
          width: 2,
        }),
      }),
    });

    const map = new ol.Map({
      layers: [baseMap, vectorLayer],  // 添加底图和矢量图层
      view: new ol.View({
        center: [-500000, 3750000],  // 设置地图中心
        projection: 'EPSG:3857',     // 使用EPSG:3857坐标系
        zoom: 4
      }),
      target: 'map'
    });

    // 历史管理器
    const historyManager = {
      undoStack: [],
      redoStack: [],
      snapshot: (feature) => {
        historyManager.undoStack.push({
          feature: feature,
          geometry: feature.getGeometry().clone()
        });
      },
      undo: () => {
        if (historyManager.undoStack.length > 0) {
          const state = historyManager.undoStack.pop();
          const currentGeometry = state.feature.getGeometry().clone();
          historyManager.redoStack.push({
            feature: state.feature,
            geometry: currentGeometry
          });
          state.feature.getGeometry().setCoordinates(state.geometry.getCoordinates());
        }
      },
      redo: () => {
        if (historyManager.redoStack.length > 0) {
          const state = historyManager.redoStack.pop();
          const currentGeometry = state.feature.getGeometry().clone();
          historyManager.undoStack.push({
            feature: state.feature,
            geometry: currentGeometry
          });
          state.feature.getGeometry().setCoordinates(state.geometry.getCoordinates());
        }
      }
    };

    // 添加交互
    const modify = new ol.interaction.Modify({
      source: vectorSource,
      insertVertexCondition: () => true  // 允许插入顶点
    });

    modify.on('modifyend', (e) => {
      e.features.forEach(feature => {
        historyManager.snapshot(feature);
      });
    });

    map.addInteraction(modify);
    historyManager.snapshot(feature);

    // 监听键盘事件
    document.addEventListener('keydown', (e) => {
      if ((e.ctrlKey || e.metaKey) && !e.altKey) {
        switch (e.key.toLowerCase()) {
          case 'z':
            if (!e.shiftKey) {
              e.preventDefault();
              historyManager.undo();
            }
            break;
          case 'y':
            if (!e.shiftKey) {
              e.preventDefault();
              historyManager.redo();
            }
            break;
        }
      }
    });
相关推荐
-凌凌漆-8 分钟前
【npm】npm的-D选项介绍
前端·npm·node.js
鹿心肺语29 分钟前
前端HTML转PDF的两种主流方案深度解析
前端·javascript
海石1 小时前
去到比北方更北的地方—2025年终总结
前端·ai编程·年终总结
一个懒人懒人1 小时前
Promise async/await与fetch的概念
前端·javascript·html
Mintopia1 小时前
Web 安全与反编译源码下的权限设计:构筑前后端一致的防护体系
前端·安全
输出输入1 小时前
前端核心技术
开发语言·前端
Mintopia1 小时前
Web 安全与反编译源码下的权限设计:构建前后端一体的信任防线
前端·安全·编译原理
林深现海1 小时前
Jetson Orin nano/nx刷机后无法打开chrome/firefox浏览器
前端·chrome·firefox
黄诂多2 小时前
APP原生与H5互调Bridge技术原理及基础使用
前端
前端市界2 小时前
用 React 手搓一个 3D 翻页书籍组件,呼吸海浪式翻页,交互体验带感!
前端·架构·github