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;
        }
      }
    });
相关推荐
风月说与山鬼17 小时前
二、React入口文件(main.jsx)
前端·react.js
东风破_1 天前
Docker 基础:为什么需要容器?
前端·后端·nginx
东风破_1 天前
Docker 实战:使用 Nginx 作为容器入口代理 Node 服务
前端·后端·nginx
你别说话了1 天前
Vue项目解决跨域
前端·javascript·vue.js
唐青枫1 天前
http-server:别再双击 index.html,一条命令把目录变成网站
前端·javascript
网安蟹佬霸1 天前
OSINT开源情报收集实战:从信息搜集到资产测绘(2026最新万字保姆级指南)
前端·网络·安全·web安全·网络安全·开源
a1117761 天前
3D历史建筑展览馆 THreeJS 开源
前端·开源
单线程_011 天前
【源码阅读】Vue3 Tokenizer 词法分析器完整状态机流转深度梳理(3.4+ 新版架构)
前端
PBitW1 天前
PM 丢来 3 个 Excel、12 个功能、4 种情形?用 TRAE Work 30 分钟整理成前端开发文档
前端·trae
风骏时光牛马1 天前
AIAgent高可用架构:弹性容错与故障自愈的落地实践
前端