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;
        }
      }
    });
相关推荐
爱喝白开水a1 小时前
前端AI自动化测试:brower-use调研让大模型帮你做网页交互与测试
前端·人工智能·大模型·prompt·交互·agent·rag
董世昌411 小时前
深度解析ES6 Set与Map:相同点、核心差异及实战选型
前端·javascript·es6
吃杠碰小鸡3 小时前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone3 小时前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09013 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农3 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king4 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
夏幻灵5 小时前
HTML5里最常用的十大标签
前端·html·html5
Mr Xu_5 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js
未来龙皇小蓝5 小时前
RBAC前端架构-01:项目初始化
前端·架构