删除连线操作

This commit is contained in:
YHH
2025-06-18 15:43:17 +08:00
parent 96f651b7ca
commit 92125aee3a
4 changed files with 83 additions and 6 deletions

View File

@@ -303,6 +303,27 @@ export function useBehaviorTreeEditor() {
alert(message);
};
// 清除所有连接线
const clearAllConnections = () => {
if (appState.connections.value.length === 0) {
alert('当前没有连接线需要清除!');
return;
}
if (confirm(`确定要清除所有 ${appState.connections.value.length} 条连接线吗?此操作不可撤销。`)) {
// 清除所有节点的父子关系
appState.treeNodes.value.forEach(node => {
node.parent = undefined;
node.children = [];
});
// 清空连接数组
appState.connections.value = [];
alert('已清除所有连接线!');
}
};
onMounted(() => {
const appContainer = document.querySelector('#behavior-tree-app');
if (appContainer) {
@@ -321,15 +342,28 @@ export function useBehaviorTreeEditor() {
alert('文件加载失败: ' + event.detail.error);
};
// 键盘快捷键处理
const handleKeydown = (event: KeyboardEvent) => {
// Delete键删除选中的节点
if (event.key === 'Delete' && appState.selectedNodeId.value) {
event.preventDefault();
nodeOps.deleteNode(appState.selectedNodeId.value);
}
// Escape键取消连接
if (event.key === 'Escape' && connectionState.isConnecting) {
event.preventDefault();
connectionManager.cancelConnection();
}
};
document.addEventListener('load-behavior-tree-file', handleLoadBehaviorTreeFile as EventListener);
document.addEventListener('file-load-error', handleFileLoadError as EventListener);
console.log('[BehaviorTreeEditor] 事件系统准备完成(直接方法调用 + DOM事件备用');
document.addEventListener('keydown', handleKeydown);
onUnmounted(() => {
console.log('[BehaviorTreeEditor] 清理事件监听器');
document.removeEventListener('load-behavior-tree-file', handleLoadBehaviorTreeFile as EventListener);
document.removeEventListener('file-load-error', handleFileLoadError as EventListener);
document.removeEventListener('keydown', handleKeydown);
// 清理暴露的方法
if (appContainer) {
@@ -361,6 +395,7 @@ export function useBehaviorTreeEditor() {
startNodeDrag,
dragState,
autoLayout,
validateTree
validateTree,
clearAllConnections
};
}

View File

@@ -473,11 +473,47 @@ export function useConnectionManager(
}, 50); // 50ms延迟确保DOM渲染完成
};
// 删除连接线
const removeConnection = (connectionId: string) => {
const connection = connections.value.find(conn => conn.id === connectionId);
if (!connection) return;
const parentNode = treeNodes.value.find(n => n.id === connection.sourceId);
const childNode = treeNodes.value.find(n => n.id === connection.targetId);
if (parentNode && childNode) {
// 从父节点的children中移除
const index = parentNode.children.indexOf(connection.targetId);
if (index > -1) {
parentNode.children.splice(index, 1);
}
// 清除子节点的parent
childNode.parent = undefined;
// 更新连接线
updateConnections();
}
};
// 连接线点击事件处理
const onConnectionClick = (event: MouseEvent, connectionId: string) => {
event.preventDefault();
event.stopPropagation();
// 询问用户是否要删除连接
if (confirm('确定要删除这条连接线吗?')) {
removeConnection(connectionId);
}
};
return {
getPortPosition,
startConnection,
cancelConnection,
updateConnections,
removeConnection,
onConnectionClick,
onPortHover,
onPortLeave,
isValidConnectionTarget

View File

@@ -281,12 +281,15 @@
transition: none;
opacity: 0.9;
will-change: d;
pointer-events: stroke;
cursor: pointer;
}
.connection-line:hover {
stroke: #9f7aea;
stroke-width: 4;
stroke: #f56565;
stroke-width: 5;
opacity: 1;
filter: drop-shadow(0 0 4px rgba(245, 101, 101, 0.6));
}
.connection-active {

View File

@@ -152,6 +152,7 @@
<button @click="centerView">居中</button>
<button @click="autoLayout">自动布局</button>
<button @click="validateTree">验证</button>
<button @click="clearAllConnections" title="清除所有连接线" v-if="connections.length > 0">清除连线</button>
</div>
</div>
@@ -186,6 +187,8 @@
:d="connection.path"
class="connection-line"
:class="{ 'connection-active': connection.active }"
@click="onConnectionClick($event, connection.id)"
:title="'点击删除连接线 (' + connection.sourceId + ' → ' + connection.targetId + ')'"
/>
<!-- 临时连接线 -->
<path