feat(map-toolbar): 新增连续测距功能,支持多段测量并显示距离

This commit is contained in:
xudan 2025-10-17 14:53:44 +08:00
parent d5e226c3cf
commit c4a098d137

View File

@ -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<Array<{ x: number; y: number }>>([]);
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;
}
// scaleratioratio退
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({
<div
class="measure-overlay"
:class="{ active: measuring }"
@mousedown="onMouseDownOverlay"
@mousemove="onMouseMoveOverlay"
@mousedown="onMeasureDown"
@dblclick="onMeasureDblClick"
>
<svg class="measure-svg" xmlns="http://www.w3.org/2000/svg">
<g v-if="measuring && start && (end || current)">
@ -230,6 +303,31 @@ defineOptions({
<g v-else-if="measuring">
<text x="20" y="40" fill="#fff" font-size="13">提示依次点击两点进行测量 Esc 退出</text>
</g>
<!-- 连续测距附加绘制以米与上方原像素测距并存仅在 measuring=true 时显示 -->
<g v-if="measuring">
<defs>
<marker id="arrow" markerWidth="6" markerHeight="6" refX="5" refY="3" orient="auto">
<path d="M0,0 L0,6 L6,3 z" fill="#1e90ff" />
</marker>
</defs>
<template v-if="mPts.length > 1">
<template v-for="(pt, idx) in mPts" :key="'seg2-'+idx">
<line v-if="idx > 0"
:x1="mPts[idx-1].x" :y1="mPts[idx-1].y"
:x2="pt.x" :y2="pt.y"
stroke="#1e90ff" stroke-width="2" />
</template>
</template>
<template v-for="(pt, idx) in mPts" :key="'dot2-'+idx">
<circle :cx="pt.x" :cy="pt.y" r="4" fill="#1e90ff" />
</template>
<g :transform="`translate(${lastAnchor2.x}, ${lastAnchor2.y - 16})`">
<rect x="-60" y="-18" width="120" height="20" rx="4" ry="4" fill="rgba(0,0,0,0.6)" />
<text x="0" y="-4" fill="#fff" font-size="12" text-anchor="middle">{{ distanceLabel2 }}</text>
</g>
</g>
</svg>
</div>
</template>