【发布时间】:2023-01-07 03:16:05
【问题描述】:
我正在实现撤消/重做功能 (with this hook)html-canvas绘图在医学(.nii)图像上做出反应。这些图像是一系列图像,表示存储在 Uint8ClampedArray 中的切片。该阵列通常约为 500(列)x 500(行)x 250(切片),换句话说,一个相当大的阵列。
我当前的解决方案只是在 mouseup 事件上从当前数组创建一个新的 Uint8ClampedArray,并将其添加到撤消/重做数组。然而,这很慢并且会造成明显的打嗝在 mouseup 事件上。我正在考虑实施更复杂的撤消/重做,它只保存受影响的体素,而不是鼠标松开时的整个阵列,但在我超越自己之前,我想知道是否有更简单的方法来优化当前的解决方案?
这是我当前的代码:
// State that stores the array of voxels for the image series.
// This updates on every brush stroke
const canvasRef = useRef(undefined);
const initialArray = canvasRef?.current?.getContext("2d")?.getImageData(canvas.width, canvas.height);
const [currentArray, setCurrentArray] = useState<Uint8ClampedArray | undefined>(initialArray);
// undo & redo states
const {
state,
setState,
resetState,
index,
lastIndex,
goBack,
goForward,
} = useUndoableState();
// Update currentArray on index change (undo/redo and draw)
useEffect(() => {
setCurrentArray(state);
}, [index]);
// Activates on mouse movement combined with left-click on canvas
function handleDrawing(){
// Logic for drawing onto the canvas
// ...
// Adds the stroke from the canvas onto the corresponding slice in the array-state
const newArray = addCanvasStrokeToArrayState(imageData, slice);
setCurrentArray(newArray);
}
function handleMouseUp() {
// This causes a hiccup every time the current state of the array is saved to the undoable array
setState(Uint8ClampedArray.from(currentArray));
}
这是撤消/重做挂钩的代码:
export default function useUndoableState(init?: TypedArray | undefined) {
const historySize = 10; // How many states to store at max
const [states, setStates] = useState([init]); // Used to store history of all states
const [index, setIndex] = useState<number>(0); // Index of current state within `states`
const state = useMemo(() => states[index], [states, index]); // Current state
const setState = (value: TypedArray) => {
// remove oldest state if history size is exceeded
let startIndex = 0;
if (states.length >= historySize) {
startIndex = 1;
}
const copy = states.slice(startIndex, index + 1); // This removes all future (redo) states after current index
copy.push(value);
setStates(copy);
setIndex(copy.length - 1);
};
// Clear all state history
const resetState = (init: TypedArray) => {
setIndex(0);
setStates([init]);
};
// Allows you to go back (undo) N steps
const goBack = (steps = 1) => {
setIndex(Math.max(0, index - steps));
};
// Allows you to go forward (redo) N steps
const goForward = (steps = 1) => {
setIndex(Math.min(states.length - 1, index + steps));
};
return {
state,
setState,
resetState,
index,
lastIndex: states.length - 1,
goBack,
goForward,
};
}
【问题讨论】:
标签: javascript reactjs canvas undo typed-arrays