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;
        }
      }
    });
相关推荐
卷福同学几秒前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端
赵庆明老师18 分钟前
Vben精讲:21-详解web-antd:tsconfig.json
前端·json·vim
wc8828 分钟前
微软EDGE浏览器功能学习
前端·学习·edge
Csvn1 小时前
🎯 原生 `<dialog>` 元素:终于可以扔掉一半的自定义弹窗组件了?
前端
Csvn1 小时前
🎨 CSS @layer:用「层叠优先级」终结样式打架的世纪难题
前端
濮水大叔2 小时前
不必把 Vue3 写成“麻花”:从状态碎片到对象协作,重新理解 Zova 的前端心智模型
前端·typescript·vue3·ioc·tsx·zova
Vuji3 小时前
MCP: 一条 tool 调用链路的旅程
前端·人工智能
万少3 小时前
DeepSeek-V4-Flash 正式版上线了,但这 3 个坑我帮你提前踩了
前端·javascript·后端
明月_清风3 小时前
🚀 Palantir Foundry 本体论实战:当 Ontology 从"知识图谱"进化为"企业操作系统"
前端·后端
驳是3 小时前
入坑 Nginx,看这一篇就够了
前端