diff --git a/src/screens/Map.jsx b/src/screens/Map.jsx new file mode 100644 index 0000000..0b047ef --- /dev/null +++ b/src/screens/Map.jsx @@ -0,0 +1,127 @@ +import { WAYPOINTS, ROUTES } from '../constants.js' + +// H3 res-5 cell centre coordinates — hardcoded, h3-js not in browser bundle +// Cross-checked against constants.js H3 IDs +const CENTRES = { + ostia: { lat: 41.73, lng: 12.23 }, + capua: { lat: 41.09, lng: 14.21 }, + brundisium: { lat: 40.63, lng: 17.94 }, + carthago: { lat: 36.86, lng: 10.32 }, + alexandria: { lat: 31.20, lng: 29.92 }, +} + +// Bounding box clipped to relevant Mediterranean — no Atlantic needed +const BBOX = { minLng: 5, maxLng: 38, minLat: 28, maxLat: 48 } +const W = 800 +const H = 460 + +function project(lat, lng) { + const x = ((lng - BBOX.minLng) / (BBOX.maxLng - BBOX.minLng)) * W + const y = ((BBOX.maxLat - lat) / (BBOX.maxLat - BBOX.minLat)) * H + return { x, y } +} + +// Rough Mediterranean land outline — placeholder, will be replaced +const LAND = [ + [43.4,5.3],[41.4,2.2],[40.4,0.7],[39.4,0.2],[38.0,0.1],[37.4,0.8], + [36.8,2.3],[36.2,5.4],[36.9,10.2],[37.1,11.1],[33.0,12.0],[32.9,14.0], + [32.1,15.0],[30.8,19.8],[30.9,25.2],[31.2,25.3],[31.5,28.0],[31.5,32.3], + [31.2,34.2],[33.0,35.1],[35.5,36.2],[36.5,36.2],[36.8,36.6], + [36.5,36.0],[35.4,34.6],[35.5,35.9],[36.5,36.2],[36.8,36.6], + [37.0,36.2],[37.5,36.8],[36.8,28.0],[37.0,27.2],[37.5,27.0], + [38.6,26.8],[39.1,26.4],[39.5,26.1],[40.2,26.3],[40.8,26.0], + [41.7,26.4],[41.5,28.0],[40.6,22.9],[40.0,22.6],[39.4,22.5], + [38.5,22.0],[37.5,21.1],[36.7,21.9],[37.5,22.4],[38.2,23.6], + [40.0,23.5],[40.5,23.0],[41.3,19.4],[42.4,18.5],[43.5,16.9], + [44.5,14.5],[45.8,13.6],[45.5,13.8],[44.4,12.3],[43.5,13.5], + [41.7,13.7],[40.9,15.6],[40.1,18.4],[38.1,15.7],[37.5,15.0], + [38.2,13.0],[37.1,11.8],[38.4,9.4],[39.0,8.9],[39.8,9.6], + [41.2,9.3],[41.9,8.7],[43.0,9.4],[43.8,7.4],[43.5,5.3], +] + +const ROUTE_ORDER = ['olive', 'wine', 'grain', 'linen'] +const WAYPOINT_IDS = ['ostia', 'capua', 'brundisium', 'carthago', 'alexandria'] + +export default function Map({ state }) { + const chapter = state?.chapter ?? 1 + + const pts = {} + Object.entries(CENTRES).forEach(([id, { lat, lng }]) => { + pts[id] = project(lat, lng) + }) + + const currentId = WAYPOINT_IDS[Math.min(chapter - 1, 4)] + + const landPath = LAND.map((c, i) => { + const { x, y } = project(c[0], c[1]) + return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}` + }).join(' ') + ' Z' + + return ( +
+ + {/* Sea */} + + + {/* Land */} + + + {/* Routes */} + {ROUTE_ORDER.map((routeId) => { + const route = ROUTES.find((r) => r.id === routeId) + if (!route) return null + const a = pts[route.from] + const b = pts[route.to] + const unlocked = chapter > route.chapter + return ( + + ) + })} + + {/* Waypoints */} + {WAYPOINT_IDS.map((id) => { + const wp = WAYPOINTS[id] + const { x, y } = pts[id] + const isCurrent = id === currentId + const isReached = WAYPOINT_IDS.indexOf(id) < chapter - 1 + return ( + + {isCurrent && ( + + )} + + + {wp.latin} + + + ) + })} + +
+ ) +}