diff --git a/src/services/editor.service.ts b/src/services/editor.service.ts index 4174c98..c6a0920 100644 --- a/src/services/editor.service.ts +++ b/src/services/editor.service.ts @@ -29,6 +29,8 @@ import { clone, get, isEmpty, isNil, isString, nth, omitBy, pick, remove, some } import { BehaviorSubject, debounceTime, filter, map, Subject, switchMap } from 'rxjs'; import { reactive, watch } from 'vue'; +import { LayerManagerService } from './layer-manager.service'; + /** * 场景编辑器服务类 * 继承自Meta2D,提供完整的场景编辑功能 @@ -41,6 +43,9 @@ import { reactive, watch } from 'vue'; * - 自定义绘制和渲染逻辑 */ export class EditorService extends Meta2d { + /** 图层管理服务实例 */ + private readonly layerManager: LayerManagerService; + //#region 场景文件管理 /** * 加载场景文件到编辑器 @@ -71,8 +76,8 @@ export class EditorService extends Meta2d { this.#loadSceneRoutes(routes, isImport); await this.#loadSceneAreas(areas, isImport); - // 确保加载的点位在路线上方 - this.#ensurePointsOnTop(); + // 确保正确的层级顺序:路线 < 点位 < 机器人 + this.#ensureCorrectLayerOrder(); this.store.historyIndex = undefined; this.store.histories = []; @@ -502,14 +507,11 @@ export class EditorService extends Meta2d { } /** - * 确保所有点位在路线上方 - * 将所有点位移到绘制顺序的最上层 + * 确保正确的层级顺序 + * 委托给图层管理服务处理 */ - #ensurePointsOnTop(): void { - const points = this.find('point'); - if (points.length > 0) { - this.top(points); - } + #ensureCorrectLayerOrder(): void { + this.layerManager.ensureCorrectLayerOrder(); } //#endregion @@ -984,8 +986,8 @@ export class EditorService extends Meta2d { pen.y! -= pen.height! / 2; const addedPen = await this.addPen(pen, false, true, true); - // 将点位移到最上层,确保它们始终显示在路线之上 - this.top([addedPen]); + // 将新创建的点位移到最上层 + this.layerManager.adjustElementLayer(addedPen); } public updatePoint(id: string, info: Partial): void { @@ -1195,6 +1197,9 @@ export class EditorService extends Meta2d { constructor(container: HTMLDivElement) { super(container, EDITOR_CONFIG); + // 初始化图层管理服务 + this.layerManager = new LayerManagerService(this); + // 禁用第6个子元素的拖放功能 (container.children.item(5)).ondrop = null; // 监听所有画布事件 diff --git a/src/services/layer-manager.service.ts b/src/services/layer-manager.service.ts new file mode 100644 index 0000000..de7ac5a --- /dev/null +++ b/src/services/layer-manager.service.ts @@ -0,0 +1,154 @@ +/* eslint-disable indent */ +import type { MapPen } from '@api/map'; +import type { Meta2d } from '@meta2d/core'; + +/** + * 图层管理服务 + * 负责管理场景编辑器中各种元素的渲染层级顺序 + * + * 层级策略(从底到顶): + * 1. 区域(area)- 最底层,作为背景 + * 2. 路线(route)- 中间层,在区域之上但在点位之下 + * 3. 点位(point)和机器人(robot)- 最上层,保持最高交互优先级 + */ +export class LayerManagerService { + constructor(private editor: Meta2d) {} + + /** + * 确保所有元素按照正确的层级顺序排列 + * 这是主要的层级管理方法,应在以下情况调用: + * - 场景加载完成后 + * - 创建新元素后 + * - 机器人初始化后 + */ + public ensureCorrectLayerOrder(): void { + const areas = this.editor.find('area'); + const routes = this.editor.find('route'); + const points = this.editor.find('point'); + const robots = this.editor.find('robot'); + + // 将区域移到最底层(作为背景) + if (areas.length > 0) { + this.editor.bottom(areas); + } + + // 将路线移到中间层(在区域之上,但在点位之下) + if (routes.length > 0) { + this.editor.top(routes); + } + + // 将点位和机器人都移到最上层(在路线之上) + const topElements = [...points, ...robots]; + if (topElements.length > 0) { + this.editor.top(topElements); + } + } + + /** + * 将指定的点位移到最上层 + * 用于新创建的点位或需要提升优先级的点位 + * @param points 要移到上层的点位数组 + */ + public movePointsToTop(points: MapPen[]): void { + if (points.length > 0) { + this.editor.top(points); + // 确保机器人仍然与点位在同一层级 + this.ensureRobotsAtTop(); + } + } + + /** + * 将指定的路线移到中间层 + * 确保路线在区域之上但在点位之下 + * @param routes 要调整层级的路线数组 + */ + public moveRoutesToMiddle(routes: MapPen[]): void { + if (routes.length > 0) { + // 先移到顶层,然后通过完整的层级管理确保正确顺序 + this.editor.top(routes); + this.ensureCorrectLayerOrder(); + } + } + + /** + * 将指定的区域移到最底层 + * 确保区域作为背景不干扰其他元素的交互 + * @param areas 要移到底层的区域数组 + */ + public moveAreasToBottom(areas: MapPen[]): void { + if (areas.length > 0) { + this.editor.bottom(areas); + } + } + + /** + * 确保机器人在最上层 + * 与点位保持同一层级,避免被其他元素覆盖 + */ + public ensureRobotsAtTop(): void { + const robots = this.editor.find('robot'); + if (robots.length > 0) { + this.editor.top(robots); + } + } + + /** + * 处理单个元素的层级 + * 根据元素类型自动调整到对应的层级 + * @param pen 要调整层级的图形元素 + */ + public adjustElementLayer(pen: MapPen): void { + switch (pen.name) { + case 'area': + this.moveAreasToBottom([pen]); + break; + case 'route': + this.moveRoutesToMiddle([pen]); + break; + case 'point': + this.movePointsToTop([pen]); + break; + case 'robot': + this.ensureRobotsAtTop(); + break; + default: + // 对于未知类型,使用完整的层级管理 + this.ensureCorrectLayerOrder(); + break; + } + } + + /** + * 重置所有元素的层级 + * 强制重新排列所有元素的层级顺序 + * 用于解决层级混乱的情况 + */ + public resetAllLayers(): void { + this.ensureCorrectLayerOrder(); + } + + /** + * 获取当前的层级信息(用于调试) + * @returns 当前各类型元素的数量和顺序信息 + */ + public getLayerInfo(): { + areas: number; + routes: number; + points: number; + robots: number; + total: number; + } { + const areas = this.editor.find('area'); + const routes = this.editor.find('route'); + const points = this.editor.find('point'); + const robots = this.editor.find('robot'); + + return { + areas: areas.length, + routes: routes.length, + points: points.length, + robots: robots.length, + total: areas.length + routes.length + points.length + robots.length, + }; + } +}