import mapboxgl from 'mapbox-gl'; import { MAPBOX_TOKEN, MAP_CONFIG, HOME_BASE, COLORS } from '../config.js'; import { FlightPathLayer } from '../webgl/FlightPathLayer.js'; export class MapView { constructor(container, options = {}) { this.container = container; this.markers = new window.Map(); this.homeMarker = null; this.onEventSelect = options.onEventSelect || (() => {}); this.flightPathLayer = null; this.init(); } init() { mapboxgl.accessToken = MAPBOX_TOKEN; this.map = new mapboxgl.Map({ container: this.container, ...MAP_CONFIG }); this.map.on('load', () => { this.addHomeBase(); this.flightPathLayer = new FlightPathLayer(this.map); this.map.resize(); }); this.map.addControl(new mapboxgl.NavigationControl(), 'top-left'); } addHomeBase() { const el = document.createElement('div'); el.className = 'home-marker'; el.innerHTML = ` `; this.homeMarker = new mapboxgl.Marker({ element: el, anchor: 'center' }) .setLngLat(HOME_BASE.coordinates) .addTo(this.map); } setEvents(events) { this.events = events; // Clear existing markers this.markers.forEach(marker => marker.remove()); this.markers.clear(); events.forEach(event => { const el = this.createMarkerElement(event); const marker = new mapboxgl.Marker({ element: el, anchor: 'center' }) .setLngLat(event.location.coordinates) .addTo(this.map); el.addEventListener('click', () => { this.onEventSelect(event); }); this.markers.set(event.id, marker); }); } createMarkerElement(event) { const el = document.createElement('div'); el.className = `event-marker ${event.type}`; const color = event.type === 'international' ? COLORS.blue : COLORS.red; el.innerHTML = ` `; return el; } flyTo(coordinates, zoom = 9) { this.map.flyTo({ center: coordinates, zoom, duration: 1500, essential: true }); } selectEvent(eventId) { // Reset all markers this.markers.forEach((marker, id) => { marker.getElement().classList.remove('selected'); }); // Highlight selected marker const marker = this.markers.get(eventId); if (marker) { marker.getElement().classList.add('selected'); } } // Show full static path between two points showFlightPath(from, to) { if (this.flightPathLayer) { this.flightPathLayer.showPath(from, to); } } // Animate path being traced, call onComplete when done animateFlightPath(from, to, duration, onComplete) { if (this.flightPathLayer) { this.flightPathLayer.animatePath(from, to, duration, onComplete); } } hideFlightPath() { if (this.flightPathLayer) { this.flightPathLayer.hide(); } } resetView() { this.map.flyTo({ center: MAP_CONFIG.center, zoom: MAP_CONFIG.zoom, duration: 1000 }); this.hideFlightPath(); } zoomToFrance() { this.map.flyTo({ center: MAP_CONFIG.center, zoom: 4.3, duration: 800 }); } getMap() { return this.map; } }