From db1f76bd0c11c8a68db7122ec199c55d6087a214 Mon Sep 17 00:00:00 2001 From: tuyenio Date: Wed, 24 Jun 2026 16:02:09 +0700 Subject: [PATCH] =?UTF-8?q?fix:=20b=E1=BA=A3n=20=C4=91=E1=BB=93=20V?= =?UTF-8?q?=E1=BB=8B=20tr=C3=AD=20auto-fit,=20kh=C3=B4ng=20c=E1=BA=AFt=20?= =?UTF-8?q?=C4=91i=E1=BB=83m,=20c=C4=83n=20gi=E1=BB=AFa=20c=C3=A2n=20?= =?UTF-8?q?=C4=91=E1=BB=91i?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app/components/VirtualTour.tsx | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/app/components/VirtualTour.tsx b/src/app/components/VirtualTour.tsx index 6a415c5..62842ed 100644 --- a/src/app/components/VirtualTour.tsx +++ b/src/app/components/VirtualTour.tsx @@ -2941,14 +2941,30 @@ function MiniMap({ const nodeSize = compact ? 5.2 : 5.2; const edgeInset = nodeSize / 2; const clampMapPoint = (value: number) => THREE.MathUtils.clamp(value, edgeInset, 100 - edgeInset); - const compressOverviewY = (value: number) => 50 + (value - 50) * 0.86; + + // Auto-fit overview: co toàn bộ điểm vào khung với lề an toàn để không bị cắt. + const OVERVIEW_MARGIN = 8; + const overviewPts = scenes + .map((s) => s.mapPosition) + .filter((p): p is { x: number; y: number } => Boolean(p)); + const overviewBounds = { + minX: Math.min(...overviewPts.map((p) => p.x)), + maxX: Math.max(...overviewPts.map((p) => p.x)), + minY: Math.min(...overviewPts.map((p) => p.y)), + maxY: Math.max(...overviewPts.map((p) => p.y)), + }; + const fitOverview = (value: number, min: number, max: number) => + max - min < 0.0001 + ? 50 + : OVERVIEW_MARGIN + ((value - min) / (max - min)) * (100 - 2 * OVERVIEW_MARGIN); + const getMapPosition = (scene: TourScene) => { if (!scene.mapPosition || (!isOverview && !activeScene.mapPosition)) return null; if (isOverview) { return { - x: clampMapPoint(scene.mapPosition.x), - y: clampMapPoint(compressOverviewY(scene.mapPosition.y)), + x: clampMapPoint(fitOverview(scene.mapPosition.x, overviewBounds.minX, overviewBounds.maxX)), + y: clampMapPoint(fitOverview(scene.mapPosition.y, overviewBounds.minY, overviewBounds.maxY)), }; }