import "maplibre-gl/dist/maplibre-gl.css"; import * as maplibre from "maplibre-gl"; import * as network from "./network"; import * as vehicles from "./vehicles"; import style from "./assets/style.json"; export default class Map extends EventTarget { /** * Instantiate a map. * @param {string|HTMLElement} target HTML container to add the map to. * @param {Array} bounds Initial map bounds. * @param {string} apiKey MapTiler API key. */ constructor(target, bounds, apiKey) { super(); // Replace map key placeholder in style definition const thisStyle = JSON.parse(JSON.stringify(style)); thisStyle.sources.openmaptiles.url = ( style.sources.openmaptiles.url.replace("{key}", apiKey) ); thisStyle.glyphs = style.glyphs.replace("{key}", apiKey); // Initialize MapLibre renderer this._renderer = new maplibre.Map({ container: target, bounds, style: thisStyle, maplibreLogo: true, maxPitch: 70, }); this._renderer.on("load", () => { network.addLayers(this._renderer); vehicles.addLayers(this._renderer, courses => { this.dispatchEvent(new CustomEvent( "click-courses", {detail: courses} )); }); // Move 3D buildings to the front of custom layers this._renderer.moveLayer("building-3d"); this.dispatchEvent(new CustomEvent("ready")); }); this._renderer.addControl(new maplibre.NavigationControl()); // Last known courses state this._courses = null; // ID of a course to follow this._follow = null; } /** Stop following a course. */ unfollow() { this._follow = null; } /** * Start following a course with the camera. * @param {string} courseId The ID of the course to follow. */ follow(courseId) { if (courseId in this._courses) { this._follow = courseId; const course = this._courses[courseId]; this._renderer.flyTo({ center: course.geometry.coordinates, bearing: course.properties.bearing, pitch: 60, zoom: 20, }); } else { this._follow = null; } } /** Update the map with new courses state. */ update(courses) { this._courses = courses; vehicles.update(this._renderer, courses); if (this._follow !== null) { if (this._follow in courses) { const course = courses[this._follow]; if (course.properties.speed > 0) { this._renderer.jumpTo({ center: course.geometry.coordinates, bearing: course.properties.bearing, }); } } else { this._follow = null; } } } }