hlarcher's picture
hlarcher HF Staff
Mobile optimizations and Safran logo
878012f unverified
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 = `
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" fill="${COLORS.blue}" stroke="${COLORS.white}" stroke-width="2"/>
<path d="M12 6L16 14H8L12 6Z" fill="${COLORS.white}"/>
</svg>
`;
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 = `
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<circle cx="10" cy="10" r="8" fill="${color}" opacity="0.2"/>
<circle cx="10" cy="10" r="5" fill="${color}"/>
</svg>
`;
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;
}
}