feat: [rd] 기획디자인 연결선 삭제 + 스페이스바 패닝 기능 추가
- 연결선 클릭 선택 → Delete/Backspace로 삭제 - 우클릭 컨텍스트 메뉴에 '연결선 삭제' 항목 추가 - 스페이스바 누른 채 마우스 드래그로 캔버스 이동 (Figma/FigJam 방식) - 패닝 중 커서 grab/grabbing 변경
This commit is contained in:
@@ -504,7 +504,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="pc-wrap" id="planningCanvas" x-data="planningCanvas()" x-init="init()" @keydown.window="handleKeyDown($event)">
|
||||
<div class="pc-wrap" id="planningCanvas" x-data="planningCanvas()" x-init="init()" @keydown.window="handleKeyDown($event)" @keyup.window="handleKeyUp($event)">
|
||||
|
||||
{{-- ===== Top Toolbar ===== --}}
|
||||
<div class="pc-toolbar">
|
||||
@@ -1054,7 +1054,8 @@
|
||||
<div class="pc-cm-sep"></div>
|
||||
<div class="pc-cm-item" @click="addNodeAtMouse(paletteItems.planning[0]); hideContextMenu();">빠른 노드 추가</div>
|
||||
<div class="pc-cm-sep"></div>
|
||||
<div class="pc-cm-item danger" @click="deleteSelectedNode(); hideContextMenu();">삭제</div>
|
||||
<div class="pc-cm-item danger" x-show="selectedConnection" @click="deleteSelectedConnection(); hideContextMenu();">연결선 삭제</div>
|
||||
<div class="pc-cm-item danger" x-show="selectedNode" @click="deleteSelectedNode(); hideContextMenu();">노드 삭제</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1117,6 +1118,7 @@ function planningCanvas() {
|
||||
panning: false,
|
||||
panStartX: 0,
|
||||
panStartY: 0,
|
||||
spaceHeld: false,
|
||||
|
||||
// Connection Drawing
|
||||
drawingConnection: false,
|
||||
@@ -1509,11 +1511,22 @@ function planningCanvas() {
|
||||
|
||||
// ===== Canvas Events =====
|
||||
onCanvasMouseDown(e) {
|
||||
if (e.target.closest('.pc-node') || e.target.closest('.pc-port')) return;
|
||||
if (this.tool === 'pan' || e.button === 1) {
|
||||
if (e.target.closest('.pc-node') || e.target.closest('.pc-port')) {
|
||||
// 스페이스바 누른 채 노드 위에서도 패닝 가능
|
||||
if (this.spaceHeld) {
|
||||
this.panning = true;
|
||||
this.panStartX = e.clientX - this.panX * this.zoom;
|
||||
this.panStartY = e.clientY - this.panY * this.zoom;
|
||||
document.getElementById('canvasWrap')?.style.setProperty('cursor', 'grabbing');
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.tool === 'pan' || this.spaceHeld || e.button === 1) {
|
||||
this.panning = true;
|
||||
this.panStartX = e.clientX - this.panX * this.zoom;
|
||||
this.panStartY = e.clientY - this.panY * this.zoom;
|
||||
document.getElementById('canvasWrap')?.style.setProperty('cursor', 'grabbing');
|
||||
e.preventDefault();
|
||||
} else {
|
||||
this.selectedNode = null;
|
||||
@@ -1551,7 +1564,12 @@ function planningCanvas() {
|
||||
this.pushHistory();
|
||||
this.autoSave();
|
||||
}
|
||||
if (this.panning) { this.panning = false; }
|
||||
if (this.panning) {
|
||||
this.panning = false;
|
||||
const wrap = document.getElementById('canvasWrap');
|
||||
if (this.spaceHeld) wrap?.style.setProperty('cursor', 'grab');
|
||||
else wrap?.style.removeProperty('cursor');
|
||||
}
|
||||
if (this.drawingConnection) {
|
||||
// Check if dropped on a node port
|
||||
const target = e.target.closest('.pc-node');
|
||||
@@ -1699,11 +1717,22 @@ function planningCanvas() {
|
||||
// ===== Keyboard Shortcuts =====
|
||||
handleKeyDown(e) {
|
||||
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) return;
|
||||
|
||||
// 스페이스바: 패닝 모드 (누르고 있는 동안)
|
||||
if (e.key === ' ' || e.code === 'Space') {
|
||||
e.preventDefault();
|
||||
if (!this.spaceHeld) {
|
||||
this.spaceHeld = true;
|
||||
this._toolBeforeSpace = this.tool;
|
||||
this.tool = 'pan';
|
||||
document.getElementById('canvasWrap')?.style.setProperty('cursor', 'grab');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.key === 'Delete' || e.key === 'Backspace') {
|
||||
if (this.selectedConnection) {
|
||||
this.connections = this.connections.filter(c => c.id !== this.selectedConnection.id);
|
||||
this.selectedConnection = null;
|
||||
this.pushHistory(); this.autoSave();
|
||||
this.deleteSelectedConnection();
|
||||
} else {
|
||||
this.deleteSelectedNode();
|
||||
}
|
||||
@@ -1726,6 +1755,26 @@ function planningCanvas() {
|
||||
}
|
||||
},
|
||||
|
||||
handleKeyUp(e) {
|
||||
if (e.key === ' ' || e.code === 'Space') {
|
||||
if (this.spaceHeld) {
|
||||
this.spaceHeld = false;
|
||||
this.panning = false;
|
||||
this.tool = this._toolBeforeSpace || 'select';
|
||||
document.getElementById('canvasWrap')?.style.removeProperty('cursor');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// ===== Connection Delete =====
|
||||
deleteSelectedConnection() {
|
||||
if (!this.selectedConnection) return;
|
||||
this.connections = this.connections.filter(c => c.id !== this.selectedConnection.id);
|
||||
this.selectedConnection = null;
|
||||
this.pushHistory();
|
||||
this.autoSave();
|
||||
},
|
||||
|
||||
// ===== Context Menu =====
|
||||
showContextMenu(e) {
|
||||
this.contextMenuPos = { x: e.clientX, y: e.clientY };
|
||||
|
||||
Reference in New Issue
Block a user