From 011e7815a2ee359a34e048637696769ce31f4f42 Mon Sep 17 00:00:00 2001 From: math-pixel <59537610+math-pixel@users.noreply.github.com> Date: Wed, 27 May 2026 17:15:08 +0200 Subject: [PATCH] update gps --- src/components/ebike/Ebike.tsx | 1 + src/components/ebike/EbikeGPSMap.tsx | 52 +++++++++++++++++++++++++--- src/world/debug/TestMap.tsx | 2 ++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/components/ebike/Ebike.tsx b/src/components/ebike/Ebike.tsx index 5c3edeb..3bb9d2c 100644 --- a/src/components/ebike/Ebike.tsx +++ b/src/components/ebike/Ebike.tsx @@ -250,6 +250,7 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element { minZ: -142, maxZ: 138, }} + zoom={4} /> diff --git a/src/components/ebike/EbikeGPSMap.tsx b/src/components/ebike/EbikeGPSMap.tsx index f904989..269e9bf 100644 --- a/src/components/ebike/EbikeGPSMap.tsx +++ b/src/components/ebike/EbikeGPSMap.tsx @@ -42,6 +42,21 @@ export interface EbikeGPSMapProps { * Optional world position for the GPS screen (defaults to origin) */ position?: [number, number, number]; + + /** + * Resolution of the offscreen canvas used for the map texture. + * Higher values yield sharper rendering at the cost of GPU memory. + * Default: 1024 (1024×1024 px) + */ + canvasSize?: number; + + /** + * Zoom level applied to the map view. + * 1 = full world bounds, 2 = 2× zoom-in centred on the player, etc. + * Values < 1 zoom out beyond the calculated world bounds. + * Default: 1 + */ + zoom?: number; } /** @@ -58,6 +73,8 @@ export const EbikeGPSMap: React.FC = ({ width = 1, height = 1, position = [0, 0, 0], + canvasSize = 1024, + zoom = 1, }) => { const [waypoints, setWaypoints] = useState([]); const [mapImage, setMapImage] = useState(null); @@ -65,11 +82,20 @@ export const EbikeGPSMap: React.FC = ({ // Offscreen high-res canvas for crystal clear rendering const [offscreenCanvas] = useState(() => { const canvas = document.createElement('canvas'); - canvas.width = 1024; - canvas.height = 1024; + canvas.width = canvasSize; + canvas.height = canvasSize; return canvas; }); + // Resize the canvas whenever canvasSize changes + useEffect(() => { + offscreenCanvas.width = canvasSize; + offscreenCanvas.height = canvasSize; + if (textureRef.current) { + textureRef.current.needsUpdate = true; + } + }, [canvasSize, offscreenCanvas]); + const textureRef = useRef(null); const animTimeRef = useRef(0); @@ -123,8 +149,8 @@ export const EbikeGPSMap: React.FC = ({ img.src = mapImageUrl; }, [mapImageUrl]); - // Determine grid boundaries - const bounds = useMemo(() => { + // Determine grid boundaries (before zoom) + const baseBounds = useMemo(() => { if (worldBounds) return worldBounds; if (waypoints.length === 0) { @@ -150,6 +176,24 @@ export const EbikeGPSMap: React.FC = ({ }; }, [waypoints, worldBounds]); + // Apply zoom: shrink the view window around the player position + const bounds = useMemo(() => { + const clampedZoom = Math.max(0.1, zoom); + if (clampedZoom === 1) return baseBounds; + + const centerX = startPos.x; + const centerZ = startPos.z; + const halfW = (baseBounds.maxX - baseBounds.minX) / 2 / clampedZoom; + const halfH = (baseBounds.maxZ - baseBounds.minZ) / 2 / clampedZoom; + + return { + minX: centerX - halfW, + maxX: centerX + halfW, + minZ: centerZ - halfH, + maxZ: centerZ + halfH, + }; + }, [baseBounds, zoom, startPos]); + // Snapped positions const startPosSnapped = useMemo(() => { if (waypoints.length === 0) return null; diff --git a/src/world/debug/TestMap.tsx b/src/world/debug/TestMap.tsx index 4aa9aa0..db9dd01 100644 --- a/src/world/debug/TestMap.tsx +++ b/src/world/debug/TestMap.tsx @@ -266,6 +266,8 @@ export function TestMap({ onOctreeReady }: TestMapProps): React.JSX.Element { "minZ": -142, "maxZ": 138 }} + zoom={1} + canvasSize={900} />