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;
        }
      }
    });
相关推荐
PyHaVolask14 小时前
CSRF跨站请求伪造
android·前端·csrf
程序员海军14 小时前
我的2025:做项目、跑副业、见人、奔波、搬家、维权、再回上海
前端·程序员·年终总结
我来整一篇14 小时前
[Razor] ASP.NET Core MVC 前端组件快速使用总结
前端·asp.net·mvc
P7Dreamer14 小时前
微信小程序处理Range分片视频播放问题:前端调试全记录
前端·微信小程序
RedHeartWWW14 小时前
初识next-auth,和在实际应用中的几个基本场景(本文以v5为例,v4和v5的差别主要是在个别显式配置和api,有兴趣的同学可以看官网教程学习)
前端·next.js
C_心欲无痕14 小时前
前端页面中,如何让用户回到上次阅读的位置
前端
C_心欲无痕14 小时前
前端本地开发构建和更新的过程
前端
Mintopia14 小时前
🌱 一个小而美的核心团队能创造出哪些奇迹?
前端·人工智能·团队管理
蚊道人15 小时前
Nuxt 4 学习文档
前端·vue.js
悠哉摸鱼大王15 小时前
前端音视频学习(一)- 基本概念
前端