Files
drawNET_test/static/js/modules/hotkeys/handlers/graph.js
T
2026-04-22 12:05:03 +09:00

112 lines
4.3 KiB
JavaScript

import { state } from '../../state.js';
import { logger } from '../../utils/logger.js';
import { alignNodes, moveNodes, distributeNodes } from '../../graph/alignment.js';
import { handleMenuAction } from '../../ui/context_menu/handlers.js';
export const graphHandlers = {
// ... cleanup ...
deleteSelected: () => {
if (!state.graph) return;
const selected = state.graph.getSelectedCells();
if (selected.length === 0) return;
state.graph.removeCells(selected);
import('../../persistence.js').then(m => m.markDirty());
},
fitScreen: () => {
if (state.graph) {
state.graph.zoomToFit({ padding: 50 });
logger.high("Graph fit to screen (X6).");
}
},
zoomIn: () => state.graph?.zoom(0.2),
zoomOut: () => state.graph?.zoom(-0.2),
connectNodes: () => handleMenuAction('connect-solid'),
connectStraight: () => handleMenuAction('connect-straight'),
disconnectNodes: () => handleMenuAction('disconnect'),
undo: () => {
if (!state.graph) return;
try {
if (typeof state.graph.undo === 'function') {
state.graph.undo();
logger.info("Undo performed via graph.undo()");
} else {
const history = state.graph.getPlugin('history');
if (history) history.undo();
logger.info("Undo performed via history plugin");
}
} catch (e) {
logger.critical("Undo failed", e);
}
},
redo: () => {
if (!state.graph) return;
try {
if (typeof state.graph.redo === 'function') {
state.graph.redo();
logger.info("Redo performed via graph.redo()");
} else {
const history = state.graph.getPlugin('history');
if (history) history.redo();
logger.info("Redo performed via history plugin");
}
} catch (e) {
logger.critical("Redo failed", e);
}
},
arrangeLayout: () => {
logger.high("Auto-layout is currently disabled (Refactoring).");
},
bringToFront: () => {
if (!state.graph) return;
const selected = state.graph.getSelectedCells();
selected.forEach(cell => cell.toFront({ deep: true }));
import('../../persistence.js').then(m => m.markDirty());
},
sendToBack: () => {
if (!state.graph) return;
const selected = state.graph.getSelectedCells();
selected.forEach(cell => cell.toBack({ deep: true }));
import('../../persistence.js').then(m => m.markDirty());
},
toggleLock: () => {
if (!state.graph) return;
const selected = state.graph.getSelectedCells();
if (selected.length === 0) return;
selected.forEach(cell => {
const data = cell.getData() || {};
const isLocked = !data.locked;
cell.setData({ ...data, locked: isLocked });
cell.setProp('movable', !isLocked);
cell.setProp('deletable', !isLocked);
cell.setProp('rotatable', !isLocked);
if (isLocked) {
cell.addTools([{ name: 'boundary', args: { attrs: { stroke: '#ef4444', 'stroke-dasharray': '5,5' } } }]);
} else {
cell.removeTools();
}
});
import('../../persistence.js').then(m => m.markDirty());
logger.high(`Toggled lock for ${selected.length} elements.`);
},
alignTop: () => alignNodes('top'),
alignBottom: () => alignNodes('bottom'),
alignLeft: () => alignNodes('left'),
alignRight: () => alignNodes('right'),
alignMiddle: () => alignNodes('middle'),
alignCenter: () => alignNodes('center'),
distributeHorizontal: () => distributeNodes('horizontal'),
distributeVertical: () => distributeNodes('vertical'),
groupNodes: () => handleMenuAction('group'),
moveUp: () => moveNodes(0, -5),
moveDown: () => moveNodes(0, 5),
moveLeft: () => moveNodes(-5, 0),
moveRight: () => moveNodes(5, 0),
moveUpLarge: () => moveNodes(0, -(state.gridSpacing || 20)),
moveDownLarge: () => moveNodes(0, (state.gridSpacing || 20)),
moveLeftLarge: () => moveNodes(-(state.gridSpacing || 20), 0),
moveRightLarge: () => moveNodes((state.gridSpacing || 20), 0)
};