feat: 在地图工具栏中添加定位功能,整合 useViewState 服务,优化视图跳转逻辑

This commit is contained in:
xudan 2025-09-29 11:09:48 +08:00
parent 86489c326c
commit 495e153db9
2 changed files with 32 additions and 82 deletions

View File

@ -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({
<a-button class="icon-btn tool-btn" size="small" :title="'缩小'" @click="zoomOut">
<img src="/src/assets/icons/png/shrink.png" alt="缩小" class="toolbar-icon" />
</a-button>
<!-- <a-button class="icon-btn tool-btn" size="small" :title="'适配视图'" @click="fitView"> 适配视图 </a-button> -->
<a-button class="icon-btn tool-btn" size="small" :title="'定位'" @click="locateCenter"> 定位 </a-button>
<a-button
class="icon-btn tool-btn"
size="small"
@ -188,8 +160,6 @@ defineOptions({
>
<img src="/src/assets/icons/png/rule.png" alt="测量尺" class="toolbar-icon" :class="{ active: measuring }" />
</a-button>
<!-- <a-button class="icon-btn tool-btn" size="small" :title="'标尺'" @click="toggleRule">标尺</a-button>
<a-button class="icon-btn tool-btn" size="small" :title="'网格'" @click="toggleGrid">网格</a-button> -->
<a-button
class="icon-btn tool-btn"
size="small"
@ -205,15 +175,6 @@ defineOptions({
:class="{ active: showColorConfig }"
/>
</a-button>
<!-- <a-button class="icon-btn tool-btn" size="small" :title="'截图'" @click="exportImage">截图</a-button>
<a-button
class="icon-btn tool-btn"
size="small"
:title="isFullscreen ? '退出全屏' : '全屏'"
@click="toggleFullscreen"
>
{{ isFullscreen ? '退出全屏' : '全屏' }}
</a-button> -->
</a-space>
</div>

View File

@ -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<void> => {
const jumpToPosition = async (
editor: EditorService,
x: number,
y: number,
isRestoring = false,
scale?: number,
): Promise<void> => {
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,
};
}