From c4a098d137732ec5211aa0cd4e2215b5baa5f9a9 Mon Sep 17 00:00:00 2001 From: xudan Date: Fri, 17 Oct 2025 14:53:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(map-toolbar):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=BF=9E=E7=BB=AD=E6=B5=8B=E8=B7=9D=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=9A=E6=AE=B5=E6=B5=8B=E9=87=8F=E5=B9=B6?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E8=B7=9D=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/map-toolbar.vue | 102 ++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/src/components/map-toolbar.vue b/src/components/map-toolbar.vue index 5a94b6a..5b3b62e 100644 --- a/src/components/map-toolbar.vue +++ b/src/components/map-toolbar.vue @@ -76,6 +76,8 @@ const toggleMeasure = () => { start.value = null; end.value = null; current.value = null; + // 清理连续测距状态 + try { mPts.value = []; mCur.value = null; } catch {} } }; @@ -133,6 +135,77 @@ onBeforeUnmount(() => { window.removeEventListener('keydown', onKeydown); }); +// =============== 连续测距(以米显示)增强 =============== +// 独立的测距状态,连续点击可累加多段,双击结束 +const mPts = ref>([]); +const mCur = ref<{ x: number; y: number } | null>(null); + +const getScaleInfo = () => { + const editor = editorRef.value; + const canvasScale = editor?.store?.data?.scale ?? 1; + let mapScale = 1; + try { + const sceneJson = editor?.save?.(); + if (sceneJson) { + const sceneData = JSON.parse(sceneJson as string); + if (typeof sceneData?.scale === 'number' && sceneData.scale > 0) { + mapScale = sceneData.scale; + } + // 如果场景scale与画布缩放一致且存在ratio,则以ratio作为地图自身缩放的回退 + if ( + typeof (sceneData as any)?.scale === 'number' && + Math.abs((sceneData as any).scale - (canvasScale || 1)) < 1e-6 && + typeof (sceneData as any)?.ratio === 'number' && (sceneData as any).ratio > 0 + ) { + mapScale = (sceneData as any).ratio; + } + } + } catch {} + return { canvasScale, mapScale }; +}; + +const totalPx2 = computed(() => { + // 仅在点击时(确认的点列)计算,不随鼠标移动而变化 + if (!measuring.value) return 0; + let t = 0; + for (let i = 1; i < mPts.value.length; i++) { + const dx = mPts.value[i].x - mPts.value[i - 1].x; + const dy = mPts.value[i].y - mPts.value[i - 1].y; + t += Math.hypot(dx, dy); + } + return t; +}); + +const totalMeters2 = computed(() => { + const { canvasScale, mapScale } = getScaleInfo(); + const denom = (canvasScale || 1) * (mapScale || 1); + if (denom <= 0) return 0; + return totalPx2.value / denom; +}); + +const distanceLabel2 = computed(() => { + const d = totalMeters2.value; + if (d >= 1000) return (d / 1000).toFixed(2) + ' km'; + if (d >= 1) return d.toFixed(2) + ' m'; + return (d * 100).toFixed(1) + ' cm'; +}); + +const lastAnchor2 = computed(() => { + // 标签位置固定在最后一个确认点,避免鼠标移动触发变更 + if (mPts.value.length) return mPts.value[mPts.value.length - 1]; + return { x: 0, y: 0 }; +}); + +const onMeasureDown = (e: MouseEvent) => { + if (!measuring.value) return; + mPts.value = [...mPts.value, { x: e.clientX, y: e.clientY }]; +}; +const onMeasureDblClick = () => { + measuring.value = false; + mPts.value = []; + mCur.value = null; +}; + // 定义组件名称 defineOptions({ name: 'MapToolbar', @@ -199,8 +272,8 @@ defineOptions({
@@ -230,6 +303,31 @@ defineOptions({ 提示:依次点击两点进行测量,按 Esc 退出 + + + + + + + + + + + + + + {{ distanceLabel2 }} + +