104 lines
3.0 KiB
JavaScript
104 lines
3.0 KiB
JavaScript
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<string>} 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;
|
|
}
|
|
}
|
|
}
|
|
}
|