Files
Konquesto/src/services/map-service.ts
2026-01-26 14:44:17 +01:00

173 lines
5.0 KiB
TypeScript

// LIBRARIES
import { Map } from "@maptiler/sdk";
import { polygon } from "@turf/helpers";
import area from "@turf/area";
// PROJECT
import { SelectedFeature } from "../types/types";
import { MAP_STYLE } from "@/constants";
import { LAYERS } from "../layers";
import { layerFilterEq, layerFilterIn } from "@/utilities/layers";
import { UIService } from "./ui-service";
/**
* Service for managing map interactions and state
*/
export class MapService {
private uiService: UIService;
private selected: Array<SelectedFeature> = [];
public map: Map;
/**
* Creates a new MapService instance
* @param uiService - The UI service for updating interface elements
*/
public constructor(uiService: UIService) {
this.uiService = uiService;
this.map = new Map({
container: "map",
style: MAP_STYLE,
});
}
/**
* Loads the map and initializes all event listeners
*/
public load() {
this.map.on("load", () => {
// Aggiunge tutti i layer custom a codice per le interazioni
this.map.addLayer(LAYERS.BUILDING_HIGHLIGHT);
this.map.addLayer(LAYERS.BUILDING_SELECT);
// Handle map hover.
this.map.on("mousemove", (e) => {
// Prende le features solo di questi livelli
const features = this.map.queryRenderedFeatures(e.point, {
layers: ["building_matteo", "road_network"],
});
// Aggiorna latitudine e longitudine nel container al mouse over.
this.uiService.$lnglat.html(`${e.lngLat.lng}<br>${e.lngLat.lat}`);
if (features && features.length > 0) {
// Prendo l'ID della top level feature in hover
const hovered = features[0];
const hoveredId = hovered.id;
if (hoveredId) {
// Aggiorna l'ID della feature nel container delle informazioni.
this.uiService.$info.html(hoveredId?.toString() || "None");
this.map.setFilter(
LAYERS.BUILDING_HIGHLIGHT.id,
layerFilterEq(hoveredId),
);
this.map.getCanvas().style.cursor = "pointer";
}
} else {
this.uiService.$info.html("None");
this.map.getCanvas().style.cursor = "default";
this.map.setFilter(LAYERS.BUILDING_HIGHLIGHT.id, layerFilterEq());
}
});
this.handleClicks();
// PROVA ROUTE
// route(
// "routed-foot",
// "12.234413623809816,45.486327517344776",
// "12.228652238845827,45.48756107353653",
// ).then((res) => {
// map.addSource("route", {
// type: "geojson",
// data: {
// type: "Feature",
// properties: {},
// geometry: res.routes[0].geometry as GeoJSON.Geometry,
// },
// });
// map.addLayer({
// id: "prova",
// type: "line",
// source: "route",
// layout: {
// "line-join": "round",
// "line-cap": "round",
// },
// paint: {
// "line-color": "#FF0000", // Colore blu
// "line-width": 5, // Spessore in pixel
// "line-opacity": 0.8,
// },
// });
// });
});
}
/**
* Handles click events on map features
*/
public handleClicks() {
this.map.on("click", (e) => {
const features = this.map.queryRenderedFeatures(e.point, {
layers: ["building_matteo"],
});
if (features && features.length > 0) {
const clicked = features[0];
const clickedId: number =
typeof clicked.id == "string"
? parseInt(clicked.id)
: clicked.id || 0;
let clickedArea: number = 0.0;
// Calculate the area of the selected.
if (
clicked.geometry.type == "Polygon" &&
clicked.geometry.coordinates.length > 0
) {
let clickedCoords = clicked.geometry.coordinates[0];
let clickedPolygon = polygon([clickedCoords]);
clickedArea = Math.trunc(area(clickedPolygon));
}
// Handle "selected list" with deletion.
const i = this.selected.findIndex((u) => u.id == clickedId);
if (i !== -1) {
this.selected.splice(i, 1);
} else {
this.selected.push({
id: clickedId,
area: clickedArea,
});
}
// Update the "selected" list.
this.uiService.updateSelectedList(this.selected);
if (this.selected.length === 0) {
this.uiService.$selected.append("<div>None</div>");
}
// Sets the selected layer.
if (clickedId) {
this.map.setFilter(LAYERS.BUILDING_HIGHLIGHT.id, layerFilterEq());
this.map.setFilter(
LAYERS.BUILDING_SELECT.id,
layerFilterIn(
this.selected.map((s) => {
return s.id;
}),
),
);
this.map.getCanvas().style.cursor = "pointer";
}
} else {
this.map.getCanvas().style.cursor = "default";
}
});
}
}