UPDATE: VERSION-20260327
This commit is contained in:
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user