JavaScript is required

撤销和重做

撤销/重做系统 - 跟踪和恢复图修改

撤销/重做功能

功能概述

本示例演示图操作的撤销/重做功能实现。每次修改(添加节点、删除节点、移动节点、添加连线、删除连线)都记录在历史堆栈中,允许用户恢复或重放更改。

核心特性实现

历史堆栈管理

interface GraphAction {
    type: 'addNode' | 'removeNode' | 'moveNode' | 'addLine' | 'removeLine';
    data: any;
    timestamp: number;
}

const historyRef = useRef<GraphAction[]>([]);
const historyIndexRef = useRef(-1);

const recordAction = (action: GraphAction) => {
    // 如果不在末尾,删除任何未来历史
    historyRef.current = historyRef.current.slice(0, historyIndexRef.current + 1);
    historyRef.current.push(action);
    historyIndexRef.current++;
};

操作包装器

const addNodeWithUndo = async (node: JsonNode) => {
    await graphInstance.addNodes([node]);
    recordAction({
        type: 'addNode',
        data: { node },
        timestamp: Date.now()
    });
};

const removeNodeWithUndo = async (nodeId: string) => {
    const node = graphInstance.getNodeById(nodeId);
    await graphInstance.removeNodeById(nodeId);
    recordAction({
        type: 'removeNode',
        data: { node },
        timestamp: Date.now()
    });
};

撤销/重做实现

const undo = async () => {
    if (historyIndexRef.current < 0) return;

    const action = historyRef.current[historyIndexRef.current];
    switch (action.type) {
        case 'addNode':
            await graphInstance.removeNodeById(action.data.node.id);
            break;
        case 'removeNode':
            await graphInstance.addNodes([action.data.node]);
            break;
        case 'moveNode':
            await graphInstance.updateNode(action.data.node.id, {
                x: action.data.oldX,
                y: action.data.oldY
            });
            break;
    }
    historyIndexRef.current--;
};

const redo = async () => {
    if (historyIndexRef.current >= historyRef.current.length - 1) return;

    historyIndexRef.current++;
    const action = historyRef.current[historyIndexRef.current];
    // 重放操作...
};

创意使用场景

图编辑器:允许用户自由实验并恢复错误。

协作编辑:跟踪更改以解决冲突。

分步教程:指导用户完成图构建。

错误恢复:防止意外删除或修改。

动画录制:记录和重放图创建过程。