From 495e153db9f4a4910fe1e5ec36cfe2142eccd788 Mon Sep 17 00:00:00 2001 From: xudan Date: Mon, 29 Sep 2025 11:09:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9C=A8=E5=9C=B0=E5=9B=BE=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E6=A0=8F=E4=B8=AD=E6=B7=BB=E5=8A=A0=E5=AE=9A=E4=BD=8D?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=95=B4=E5=90=88=20useViewState=20?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=EF=BC=8C=E4=BC=98=E5=8C=96=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E8=B7=B3=E8=BD=AC=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/map-toolbar.vue | 69 ++++++++-------------------------- src/services/useViewState.ts | 45 +++++++++------------- 2 files changed, 32 insertions(+), 82 deletions(-) diff --git a/src/components/map-toolbar.vue b/src/components/map-toolbar.vue index a79f396..f7e6d74 100644 --- a/src/components/map-toolbar.vue +++ b/src/components/map-toolbar.vue @@ -3,6 +3,7 @@ import type { EditorService } from '@core/editor.service'; import { useToolbar } from '@core/useToolbar'; import { computed, inject, type InjectionKey, onBeforeUnmount, onMounted, ref, type ShallowRef } from 'vue'; +import { useViewState } from '../services/useViewState'; import ColorConfigPanel from './color/color-config-panel.vue'; // 通用地图工具栏(右下角),临时中文按钮 @@ -21,14 +22,11 @@ const editorRef = inject(props.token)!; // 颜色配置面板状态 const showColorConfig = ref(false); -// 使用 useToolbar 的相关能力(内部使用 jumpToPosition、修改 store 等) -const { - toggleGrid: _toggleGrid, - toggleRule: _toggleRule, - // fitView: _fitView, - zoomIn: _zoomIn, - zoomOut: _zoomOut, -} = useToolbar(); +// 使用 useToolbar 的相关能力 +const { toggleGrid: _toggleGrid, toggleRule: _toggleRule, zoomIn: _zoomIn, zoomOut: _zoomOut } = useToolbar(); + +// 使用 useViewState 的相关能力 +const { jumpToPosition, calculateCenterPoint } = useViewState(); const zoomIn = () => { if (editorRef.value) _zoomIn(editorRef.value); @@ -36,42 +34,16 @@ const zoomIn = () => { const zoomOut = () => { if (editorRef.value) _zoomOut(editorRef.value); }; -// const fitView = async () => { -// if (editorRef.value) await _fitView(editorRef.value); -// }; -// const toggleFullscreen = async () => { -// try { -// const el = props.containerEl || document.documentElement; -// if (!document.fullscreenElement) { -// await el.requestFullscreen?.(); -// } else { -// await document.exitFullscreen?.(); -// } -// } catch (e) { -// console.warn('全屏切换失败', e); -// } -// }; +// 定位到中心点并缩放 +const locateCenter = () => { + if (editorRef.value) { + const { centerX, centerY } = calculateCenterPoint(editorRef.value); + jumpToPosition(editorRef.value, centerX, centerY, false, 0.05); + } +}; -// const downloadBase64 = (base64: string, filename = 'map.png') => { -// const a = document.createElement('a'); -// a.href = base64; -// a.download = filename; -// document.body.appendChild(a); -// a.click(); -// document.body.removeChild(a); -// }; - -// const exportImage = () => { -// try { -// const base64 = editorRef.value?.toPng?.(2); -// if (base64) downloadBase64(base64, '地图截图.png'); -// } catch (e) { -// console.warn('截图失败', e); -// } -// }; - -// 网格/标尺开关:调用 useToolbar 封装 +// 网格/标尺开关 const toggleGrid = () => editorRef.value && _toggleGrid(editorRef.value); const toggleRule = () => editorRef.value && _toggleRule(editorRef.value); @@ -176,7 +148,7 @@ defineOptions({ 缩小 - + 定位 测量尺 - - diff --git a/src/services/useViewState.ts b/src/services/useViewState.ts index 06426cc..04fe6f8 100644 --- a/src/services/useViewState.ts +++ b/src/services/useViewState.ts @@ -205,16 +205,21 @@ export function useViewState() { * @param x X坐标 * @param y Y坐标 * @param isRestoring 是否为恢复视图状态,true时保持当前缩放比例 + * @param scale 目标缩放比例 */ - const jumpToPosition = async (editor: EditorService, x: number, y: number, isRestoring = false): Promise => { + const jumpToPosition = async ( + editor: EditorService, + x: number, + y: number, + isRestoring = false, + scale?: number, + ): Promise => { try { - // 检查是否已存在临时点 - const existingTempPoints = editor - .find('point') - .filter((point) => point.id && point.id.includes('view-center-point')); - - // 如果不是恢复状态且没有临时点,调整缩放比例到8% - if (!isRestoring && existingTempPoints.length === 0) { + // 如果传递了 scale,则无论如何都应用缩放 + if (typeof scale === 'number') { + editor.scale(scale); + } else if (!isRestoring) { + // 仅在非恢复状态且未指定 scale 时使用默认缩放 editor.scale(0.08); } @@ -239,16 +244,15 @@ export function useViewState() { editor.inactive(); }, 10); // 短暂延迟确保跳转完成 - // 延迟清理临时点(保存时已自动过滤,这里只是为了清理画布显示) + // 延迟清理临时点 setTimeout(() => { const remainingPoints = editor .find('point') .filter((point) => point.id && point.id.includes('view-center-point')); - if (remainingPoints && remainingPoints.length > 0) { + if (remainingPoints.length > 0) { editor.delete(remainingPoints); - console.log(`清理了 ${remainingPoints.length} 个临时点`); } - }, 500); // 增加延迟确保跳转完成 + }, 500); } catch (error) { console.error('跳转到指定位置失败:', error); } @@ -291,8 +295,6 @@ export function useViewState() { /** * 自动保存和恢复视图状态 - * 如果本地没有保存的key,则先保存当前状态(用于定位地图),然后恢复 - * 如果有key,则直接按原来逻辑恢复 * @param editor 编辑器服务实例 * @param sceneId 场景ID * @param groupId 群组ID (可选) @@ -306,30 +308,17 @@ export function useViewState() { const hasExistingState = hasViewState(sceneId, groupId); if (!hasExistingState) { - // 首次进入:先居中显示获取中心点坐标 editor.centerView(); - - // 等待一小段时间让centerView完成 await new Promise((resolve) => setTimeout(resolve, 100)); - - // 获取当前视图状态(主要是为了获取中心点坐标) const currentState = getCurrentViewState(editor); - - // 缩放到8%并跳转到中心点(首次进入的默认行为) await jumpToPosition(editor, currentState.centerX, currentState.centerY, false); - - // 保存当前状态(包含8%缩放和中心点坐标) await saveViewState(editor, sceneId, groupId); - return true; } else { - // 直接恢复已有状态 return await restoreViewState(editor, sceneId, groupId); } } catch (error) { console.error('自动保存和恢复视图状态失败:', error); - - // 如果出错,至少执行centerView作为fallback editor.centerView(); return false; } @@ -345,7 +334,7 @@ export function useViewState() { getViewStateInfo, getCurrentViewState, autoSaveAndRestoreViewState, - // 对外暴露跳转方法,供工具栏或其他模块使用(例如适配视图时用该方法居中跳转) jumpToPosition, + calculateCenterPoint, }; }