Я использую Cytoscape и пытаюсь запустить его, как это демо . Я преобразовал большую часть кода в React, и он в основном работает.
Проблема, с которой я столкнулся, заключается в том, чтобы заставить CTRL+Z работать так же, как в демоверсии (или любой другой ввод с клавиатуры, если на то пошло). Я знаю, что я правильно зарегистрировал плагин, потому что я могу программно отменить и повторить действия с помощью действий undo()
и redo()
.
Я не уверен, что здесь происходит, возможно, это проблема с React?
В песочнице видно, что кнопки undo
и redo
работают нормально, а вот клавиатура CTRL+Z и CTRL+Y — нет. Почему привязки клавиатуры работают в их демо, а не в моей песочнице?
Вот что у меня есть,
import React from "react";
import cytoscape, { Core as CSCore } from "cytoscape";
import CytoscapeComponent from "react-cytoscapejs";
import stylesheet from "./stylesheet";
import layout from "./layout";
import { initialNodes, initialEdges } from "./elements";
import { TEdge } from "./elements/edges";
import { TNode } from "./elements/nodes";
import undoRedo from "cytoscape-undo-redo";
cytoscape.use(undoRedo);
export default React.memo(() => {
// Nodes and edges are handles separately
const [nodes] = React.useState<TNode[]>(initialNodes);
const [edges] = React.useState<TEdge[]>(initialEdges);
// Cytoscape instance
const cyRef = React.useRef<CSCore | null>(null);
// UndoRedo instance
const urRef = React.useRef<any>(null);
const init = React.useCallback((cy: CSCore) => {
if (!cyRef.current) {
cyRef.current = cy;
}
urRef.current = cyRef.current.undoRedo({
isDebug: false, // Debug mode for console messages
actions: {}, // actions to be added
undoableDrag: true, // Whether dragging nodes are undoable can be a function as well
stackSizeLimit: undefined, // Size limit of undo stack, note that the size of redo stack cannot exceed size of undo stack
ready: function () {
// callback when undo-redo is ready
}
}); // Can also be set whenever wanted.
cyRef.current.on("afterUndo", function (e, name) {
// @ts-ignore
document.getElementById("undos").innerHTML +=
"<span style='color: darkred; font-weight: bold'>Undo: </span> " +
name +
"</br>";
});
cyRef.current.on("afterRedo", function (e, name) {
// @ts-ignore
document.getElementById("undos").innerHTML +=
"<span style='color: darkblue; font-weight: bold'>Redo: </span>" +
name +
"</br>";
});
cyRef.current.on("afterDo", function (e, name) {
// @ts-ignore
document.getElementById("undos").innerHTML +=
"<span style='color: darkmagenta; font-weight: bold'>Do: </span>" +
name +
"</br>";
});
}, []);
return (
<div>
<div id = "undoRedoList">
<span style = {{ color: "darkslateblue", fontWeight: "bold" }}>Log</span>
<div
id = "undos"
style = {{ paddingBottom: 20, position: "absolute", left: 40, top: 40 }}
/>
</div>
<div
style = {{ zIndex: 99999999, position: "absolute", right: 20, top: 20 }}
>
<button onClick = {() => urRef.current.undo()}>undo</button>
<button onClick = {() => urRef.current.redo()}>redo</button>
</div>
<CytoscapeComponent
elements = {CytoscapeComponent.normalizeElements({
nodes: nodes,
edges: edges
})}
layout = {layout}
cy = {(cy) => init(cy)}
stylesheet = {stylesheet}
style = {{
width: "100vw",
height: "100vh"
}}
/>
</div>
);
});
Единственное, что не так с вашим кодом, это отсутствие реальных ключевых слушателей. В демо-версии отмены и повтора функции crtl+z
и crtl+y
на самом деле таковы:
document.addEventListener("keydown", function(e) {
if (e.which === 46) {
var selecteds = cy.$(":selected");
if (selecteds.length > 0)
ur.do("remove", selecteds);
} else if (e.ctrlKey && e.target.nodeName === 'BODY')
if (e.which === 90)
ur.undo();
else if (e.which === 89)
ur.redo();
});
Если вы вставите это в свой код (я попробовал это после вашего прослушивателя событий «afterDo» в «index.tsx», тогда ваш откат-повтор должен работать правильно. У меня была одна проблема, когда ваш код жаловался на то, что отмена-повтор определен дважды, но это решилось само собой после перезагрузки вашей песочницы.