|
1 | 1 | import React, { useEffect, useMemo, useState } from "react"; |
2 | 2 | import dynamic from "next/dynamic"; |
3 | | -import { Circle, Marker, Polyline, Popup, Tooltip, useMapEvents } from "react-leaflet"; |
| 3 | +import { CircleMarker, Marker, Polyline, Tooltip, useMapEvents } from "react-leaflet"; |
4 | 4 | import { useTranslation } from '@/components/useTranslations'; |
5 | 5 | import 'leaflet/dist/leaflet.css'; |
6 | 6 | import customPins from '../public/customPins.json' with { type: "module" }; |
7 | 7 | import guestNameString from "@/serverUtils/guestNameFromString"; |
8 | 8 | import CountryFlag from './utils/countryFlag'; |
9 | | -const hintMul = 5000000 / 20000; //5000000 for all countries (20,000 km) |
| 9 | +const hintMul = 7500000 / 20000; //7500000 for all countries (20,000 km) |
| 10 | + |
| 11 | +// Simple seeded random for stable hint offset per round |
| 12 | +function seededRandom(seed) { |
| 13 | + const x = Math.sin(seed * 9999) * 10000; |
| 14 | + return x - Math.floor(x); |
| 15 | +} |
| 16 | + |
| 17 | +// HintCircle component that scales with zoom |
| 18 | +function HintCircle({ location, gameOptions, round }) { |
| 19 | + const [zoom, setZoom] = useState(2); |
| 20 | + |
| 21 | + const map = useMapEvents({ |
| 22 | + zoomend: () => setZoom(map.getZoom()), |
| 23 | + }); |
| 24 | + |
| 25 | + const radius = hintMul * (gameOptions?.maxDist ?? 20000); |
| 26 | + const seed = round ?? 1; |
| 27 | + const radiusDeg = radius / 111000; |
| 28 | + |
| 29 | + // Offset center by 5-95% of radius in a random direction |
| 30 | + // Use location coords as part of seed for more variation |
| 31 | + const locSeed = Math.abs(location.lat * 1000 + location.long * 1000) + seed; |
| 32 | + const offsetFraction = 0.05 + seededRandom(locSeed) * 0.9; |
| 33 | + const offsetAngle = seededRandom(locSeed * 7.3) * 2 * Math.PI; |
| 34 | + const offsetDeg = radiusDeg * offsetFraction; |
| 35 | + const centerLat = location.lat + offsetDeg * Math.cos(offsetAngle); |
| 36 | + const centerLng = location.long + offsetDeg * Math.sin(offsetAngle); |
| 37 | + |
| 38 | + // Convert meters to pixels at current zoom |
| 39 | + // At zoom 0, 1 pixel ≈ 156543 meters at equator |
| 40 | + const metersPerPixel = 156543 / Math.pow(2, zoom); |
| 41 | + const pixelRadius = radius / metersPerPixel; |
| 42 | + |
| 43 | + return ( |
| 44 | + <CircleMarker |
| 45 | + center={{ lat: centerLat, lng: centerLng }} |
| 46 | + radius={pixelRadius} |
| 47 | + className="hintCircle" |
| 48 | + /> |
| 49 | + ); |
| 50 | +} |
10 | 51 |
|
11 | 52 | // Dynamic import of react-leaflet components |
12 | 53 | const MapContainer = dynamic( |
@@ -249,7 +290,7 @@ const MapComponent = ({ shown, options, ws, session, pinPoint, setPinPoint, answ |
249 | 290 | } */} |
250 | 291 |
|
251 | 292 | {showHint && location && ( |
252 | | - <Circle center={{ lat: location.lat, lng: location.long }} radius={hintMul * (gameOptions?.maxDist) ?? 0} className="hintCircle" /> |
| 293 | + <HintCircle location={location} gameOptions={gameOptions} round={round} /> |
253 | 294 | )} |
254 | 295 |
|
255 | 296 | <TileLayer |
|
0 commit comments