UPDATE: VERSION-20260327

This commit is contained in:
libertyspy
2026-03-27 10:35:23 +08:00
parent 168ced6b27
commit cb1019b7d7
3 changed files with 68 additions and 25 deletions

View File

@@ -1,7 +1,7 @@
/* /*
* This file is part of the kernelstudio package. * This file is part of the kernelstudio package.
* *
* (c) 2014-2025 zlin <admin@kernelstudio.com> * (c) 2014-2026 zlin <admin@kernelstudio.com>
* *
* For the full copyright and license information, please view the LICENSE file * For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code. * that was distributed with this source code.
@@ -23,14 +23,14 @@ export class EventError {
export class EventListener { export class EventListener {
private readonly _listeners: Record<string, Function[]>; private _listeners: Record<string, Function[]>;
constructor(listeners: Record<string, Function[]> = {}) { constructor(listeners: Record<string, Function[]> = {}) {
this._listeners = listeners; this._listeners = listeners;
} }
all(): Record<string, Function[]> { all(): Record<string, Function[]> {
return {...this._listeners}; // 返回副本,避免外部直接修改 return { ...this._listeners }; // 返回副本,避免外部直接修改
} }
has(name: string): boolean { has(name: string): boolean {
@@ -55,16 +55,24 @@ export class EventListener {
[...listeners].forEach(f => f(options)); [...listeners].forEach(f => f(options));
} }
} }
clear(){
for (const key in this._listeners) {
if (this._listeners.hasOwnProperty(key)) {
delete this._listeners[key];
}
}
}
} }
export const safePreventDefault = (event: any) => { export const safePreventDefault = (event: any) => {
if (event && typeof event.preventDefault === 'function') { if (event && typeof event.preventDefault === 'function') {
event.preventDefault(); event.preventDefault();
} }
} };
export const safeStopPropagation = (event: any) => { export const safeStopPropagation = (event: any) => {
if (event && typeof event.stopPropagation === 'function') { if (event && typeof event.stopPropagation === 'function') {
event.stopPropagation(); event.stopPropagation();
} }
} };

View File

@@ -114,8 +114,16 @@ export default defineComponent({
fitToScreen, fitToScreen,
centerContent, centerContent,
resizeCanvas, resizeCanvas,
destroyGraph,
clearGraph,
} = useGraphCanvas(); } = useGraphCanvas();
const destroy = ()=> {
window.removeEventListener('resize', handleResize);
destroyGraph();
graph.value = null;
}
const loadPlatforms = () => { const loadPlatforms = () => {
platforms.value = []; platforms.value = [];
findAllBasicPlatforms().then(r => { findAllBasicPlatforms().then(r => {
@@ -213,6 +221,8 @@ export default defineComponent({
}; };
const handleSelectTree = (tree: BehaviorTree) => { const handleSelectTree = (tree: BehaviorTree) => {
destroyGraph();
console.info('handleSelectTree', tree); console.info('handleSelectTree', tree);
findOneTreeById(tree.id).then(r => { findOneTreeById(tree.id).then(r => {
if (r.data) { if (r.data) {
@@ -233,7 +243,9 @@ export default defineComponent({
graph: nodeGraph, graph: nodeGraph,
}; };
currentTreeEditing.value = true; currentTreeEditing.value = true;
createElements(); nextTick(() => {
initGraph();
});
} else { } else {
message.error(r.msg ?? '行为树不存在.'); message.error(r.msg ?? '行为树不存在.');
} }
@@ -241,12 +253,8 @@ export default defineComponent({
}; };
const createElements = () => { const createElements = () => {
clearGraph();
nextTick(() => { nextTick(() => {
try {
graph.value?.clearCells();
} catch (e: any) {
console.error('clear cells error, cause:', e);
}
setTimeout(() => { setTimeout(() => {
if (currentBehaviorTree.value?.graph && graph.value) { if (currentBehaviorTree.value?.graph && graph.value) {
if (currentBehaviorTree.value?.graph.nodes) { if (currentBehaviorTree.value?.graph.nodes) {
@@ -274,6 +282,8 @@ export default defineComponent({
}; };
const handleCreateTree = () => { const handleCreateTree = () => {
destroyGraph();
currentBehaviorTree.value = { currentBehaviorTree.value = {
id: 0, id: 0,
name: '行为树', name: '行为树',
@@ -294,7 +304,9 @@ export default defineComponent({
selectedModelNode.value = null; selectedModelNode.value = null;
selectedNodeTaskElement.value = null; selectedNodeTaskElement.value = null;
createElements(); nextTick(() => {
initGraph();
});
}; };
// 初始化X6画布 // 初始化X6画布
@@ -417,18 +429,7 @@ export default defineComponent({
}); });
// 清理 // 清理
onBeforeUnmount(() => { onBeforeUnmount(() => destroy());
window.removeEventListener('resize', handleResize);
if (graph.value) {
try {
graph.value.clearCells();
} catch (error) {
console.warn('销毁画布时出错:', error);
}
graph.value = null;
console.log('画布已销毁');
}
});
return { return {
platforms, platforms,

View File

@@ -7,7 +7,7 @@
* that was distributed with this source code. * that was distributed with this source code.
*/ */
import { computed, type ComputedRef, ref, type Ref } from 'vue'; import { computed, type ComputedRef, ref, type Ref, nextTick } from 'vue';
import { type Dom, Graph, Node } from '@antv/x6'; import { type Dom, Graph, Node } from '@antv/x6';
import type { NodeViewPositionEventArgs } from '@antv/x6/es/view/node/type'; import type { NodeViewPositionEventArgs } from '@antv/x6/es/view/node/type';
import { createGraphCanvas } from './canvas'; import { createGraphCanvas } from './canvas';
@@ -24,6 +24,8 @@ export interface UseGraphCanvas {
graph: ComputedRef<Graph>; graph: ComputedRef<Graph>;
zoomIn: () => void; zoomIn: () => void;
zoomOut: () => void; zoomOut: () => void;
destroyGraph: () => void;
clearGraph: () => void;
fitToScreen: () => void; fitToScreen: () => void;
centerContent: () => void; centerContent: () => void;
resizeCanvas: () => void; resizeCanvas: () => void;
@@ -39,6 +41,36 @@ export const useGraphCanvas = (readonly: boolean = false): UseGraphCanvas => {
const eventListener = new EventListener(); const eventListener = new EventListener();
const currentZoom = ref<number>(0); const currentZoom = ref<number>(0);
const clearGraph = ()=> {
if (graph.value) {
try {
graph.value.off();
graph.value.clearCells();
} catch (e) {
console.error('清空画布失败:', e);
}
}
}
const destroyGraph = ()=> {
eventListener.clear();
if (graph.value) {
clearGraph();
// 等待 Vue 完成卸载
nextTick(() => {
graph.value?.dispose(); // 销毁 Graph 实例
graph.value = null;
if (container.value) {
container.value.innerHTML = ''; // 清空容器内容
}
});
} else if (container.value) {
container.value.innerHTML = '';
}
}
const handleGraphEvent = (name: string, fn: Function) => { const handleGraphEvent = (name: string, fn: Function) => {
eventListener.on(name, fn); eventListener.on(name, fn);
}; };
@@ -243,6 +275,8 @@ export const useGraphCanvas = (readonly: boolean = false): UseGraphCanvas => {
return { return {
container, container,
readonly, readonly,
destroyGraph,
clearGraph,
graph: graphInstance, graph: graphInstance,
eventListener, eventListener,
currentZoom, currentZoom,