173 lines
5.0 KiB
TypeScript
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";
|
|
}
|
|
});
|
|
}
|
|
}
|