code re-organization
This commit is contained in:
@@ -1 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Initial zoom level for the map
|
||||||
|
*/
|
||||||
export const INITIAL_ZOOM = 17;
|
export const INITIAL_ZOOM = 17;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MapTiler style URL for the map
|
||||||
|
*/
|
||||||
|
export const MAP_STYLE = import.meta.env.VITE_MAPTILER_STYLE;
|
||||||
|
|||||||
9
src/game.ts
Normal file
9
src/game.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Game class for managing game state and logic
|
||||||
|
*/
|
||||||
|
class Game {
|
||||||
|
/**
|
||||||
|
* Starts the game
|
||||||
|
*/
|
||||||
|
public start = () => {};
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import { FillLayerSpecification, LineLayerSpecification } from "@maptiler/sdk";
|
import { FillLayerSpecification } from "@maptiler/sdk";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for all custom map layers
|
||||||
|
*/
|
||||||
export const LAYERS = {
|
export const LAYERS = {
|
||||||
|
/** Layer for highlighting hovered buildings */
|
||||||
BUILDING_HIGHLIGHT: {
|
BUILDING_HIGHLIGHT: {
|
||||||
id: "building-highlight",
|
id: "building-highlight",
|
||||||
type: "fill",
|
type: "fill",
|
||||||
@@ -13,6 +17,7 @@ export const LAYERS = {
|
|||||||
filter: ["==", ["id"], ""],
|
filter: ["==", ["id"], ""],
|
||||||
} as FillLayerSpecification,
|
} as FillLayerSpecification,
|
||||||
|
|
||||||
|
/** Layer for highlighting selected buildings */
|
||||||
BUILDING_SELECT: {
|
BUILDING_SELECT: {
|
||||||
id: "building-select",
|
id: "building-select",
|
||||||
type: "fill",
|
type: "fill",
|
||||||
@@ -24,17 +29,4 @@ export const LAYERS = {
|
|||||||
},
|
},
|
||||||
filter: ["==", ["id"], ""],
|
filter: ["==", ["id"], ""],
|
||||||
} as FillLayerSpecification,
|
} as FillLayerSpecification,
|
||||||
|
|
||||||
ROAD_HIGHLIGHT: {
|
|
||||||
id: "road-highlight",
|
|
||||||
type: "line",
|
|
||||||
paint: {
|
|
||||||
"line-color": "#FF0000",
|
|
||||||
"line-width": 4,
|
|
||||||
"line-opacity": 1,
|
|
||||||
},
|
|
||||||
source: "maptiler_planet_v4",
|
|
||||||
"source-layer": "road",
|
|
||||||
filter: ["==", ["id"], ""],
|
|
||||||
} as LineLayerSpecification,
|
|
||||||
};
|
};
|
||||||
|
|||||||
191
src/main.ts
191
src/main.ts
@@ -6,18 +6,16 @@ import "@maptiler/sdk/dist/maptiler-sdk.css";
|
|||||||
|
|
||||||
// LIBRARIES
|
// LIBRARIES
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import { FilterSpecification, Map, config } from "@maptiler/sdk";
|
import { config } from "@maptiler/sdk";
|
||||||
import { createIcons, Locate, LocateFixed } from "lucide";
|
import { createIcons, Locate, LocateFixed } from "lucide";
|
||||||
import area from "@turf/area";
|
|
||||||
import { polygon } from "@turf/helpers";
|
|
||||||
|
|
||||||
// PROJECT
|
// PROJECT
|
||||||
import { LAYERS } from "@/layers";
|
import { panToCurrentLocation } from "@/utilities/geo";
|
||||||
import { panToCurrentLocation, route } from "@/utilities/geo";
|
import { MapService } from "@/services/map-service";
|
||||||
|
import { UIService } from "./services/ui-service";
|
||||||
|
|
||||||
// ENV
|
// ENV
|
||||||
const API_KEY = import.meta.env.VITE_MAPTILER_API_KEY || "";
|
const API_KEY = import.meta.env.VITE_MAPTILER_API_KEY || "";
|
||||||
const MAP_STYLE = import.meta.env.VITE_MAPTILER_STYLE;
|
|
||||||
|
|
||||||
createIcons({
|
createIcons({
|
||||||
icons: {
|
icons: {
|
||||||
@@ -26,187 +24,14 @@ createIcons({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO
|
|
||||||
// WEBSOCKET TBD!!
|
|
||||||
// const ws = new WebSocket(`ws://${import.meta.env.VITE_SERVER_URL}/ws`);
|
|
||||||
// ws.onopen = () => {
|
|
||||||
// console.log("opened");
|
|
||||||
// };
|
|
||||||
// ws.onmessage = (ev) => {
|
|
||||||
// console.log("il server dice");
|
|
||||||
// console.log(ev.data);
|
|
||||||
// };
|
|
||||||
|
|
||||||
config.apiKey = API_KEY;
|
config.apiKey = API_KEY;
|
||||||
|
|
||||||
interface SelectedFeature {
|
const mapService = new MapService(new UIService());
|
||||||
id: number;
|
mapService.load();
|
||||||
area: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $info = $("#layer");
|
|
||||||
const $lnglat = $("#lnglat");
|
|
||||||
const $selected = $("#selected");
|
|
||||||
|
|
||||||
let selected: Array<SelectedFeature> = [];
|
|
||||||
|
|
||||||
const map = new Map({
|
|
||||||
container: "map",
|
|
||||||
style: MAP_STYLE,
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#locate").on("click", (e) => {
|
$("#locate").on("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
panToCurrentLocation(map);
|
panToCurrentLocation(mapService.map);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Funzione helper per settare i filtri dei layer.
|
panToCurrentLocation(mapService.map);
|
||||||
// Per non avere array hardcoded.]
|
|
||||||
const layerFilterEq = (id?: string | number) => {
|
|
||||||
return ["==", ["id"], id ? id : ""] as FilterSpecification;
|
|
||||||
};
|
|
||||||
const layerFilterIn = (ids: Array<string | number | undefined>) => {
|
|
||||||
return ["in", ["id"], ["literal", ids]] as FilterSpecification;
|
|
||||||
};
|
|
||||||
|
|
||||||
map.on("load", () => {
|
|
||||||
// Aggiunge tutti i layer custom a codice per le interazioni
|
|
||||||
map.addLayer(LAYERS.BUILDING_HIGHLIGHT);
|
|
||||||
map.addLayer(LAYERS.BUILDING_SELECT);
|
|
||||||
map.addLayer(LAYERS.ROAD_HIGHLIGHT);
|
|
||||||
|
|
||||||
// Handle map hover.
|
|
||||||
map.on("mousemove", (e) => {
|
|
||||||
// Prende le features solo di questi livelli
|
|
||||||
const features = map.queryRenderedFeatures(e.point, {
|
|
||||||
layers: ["building_matteo", "road_network"],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Aggiorna latitudine e longitudine nel container al mouse over.
|
|
||||||
$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;
|
|
||||||
|
|
||||||
// Aggiorna l'ID della feature nel container delle informazioni.
|
|
||||||
$info.html(hoveredId?.toString() || "");
|
|
||||||
|
|
||||||
if (hoveredId) {
|
|
||||||
map.setFilter(LAYERS.BUILDING_HIGHLIGHT.id, layerFilterEq(hoveredId));
|
|
||||||
// map.setFilter(LAYERS.ROAD_HIGHLIGHT.id, layerFilterEq(hoveredId));
|
|
||||||
map.getCanvas().style.cursor = "pointer";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
map.getCanvas().style.cursor = "default";
|
|
||||||
map.setFilter(LAYERS.BUILDING_HIGHLIGHT.id, layerFilterEq());
|
|
||||||
// map.setFilter(LAYERS.ROAD_HIGHLIGHT.id, layerFilterEq());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle map click.
|
|
||||||
map.on("click", (e) => {
|
|
||||||
const features = 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;
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// WEBSOCKET TBD!
|
|
||||||
// ws.send(
|
|
||||||
// JSON.stringify({
|
|
||||||
// clicked: clickedId,
|
|
||||||
// }),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// 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 = selected.findIndex((u) => u.id == clickedId);
|
|
||||||
if (i !== -1) {
|
|
||||||
selected.splice(i, 1);
|
|
||||||
} else {
|
|
||||||
selected.push({
|
|
||||||
id: clickedId,
|
|
||||||
area: clickedArea,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the "selected" list.
|
|
||||||
const selectedList = $("<ul>");
|
|
||||||
selected.forEach((feature) => {
|
|
||||||
selectedList.append(
|
|
||||||
`<li>${feature.id} (${feature.area} m<sup>2</sup>)</li>`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$selected.empty().append(selectedList);
|
|
||||||
|
|
||||||
if (selected.length === 0) {
|
|
||||||
$selected.append("<div>None</div>");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the selected layer.
|
|
||||||
if (clickedId) {
|
|
||||||
map.setFilter(LAYERS.BUILDING_HIGHLIGHT.id, layerFilterEq());
|
|
||||||
map.setFilter(
|
|
||||||
LAYERS.BUILDING_SELECT.id,
|
|
||||||
layerFilterIn(
|
|
||||||
selected.map((s) => {
|
|
||||||
return s.id;
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
map.getCanvas().style.cursor = "pointer";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
map.getCanvas().style.cursor = "default";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
panToCurrentLocation(map);
|
|
||||||
|
|||||||
172
src/services/map-service.ts
Normal file
172
src/services/map-service.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
// Aggiorna l'ID della feature nel container delle informazioni.
|
||||||
|
this.uiService.$info.html(hoveredId?.toString() || "");
|
||||||
|
|
||||||
|
if (hoveredId) {
|
||||||
|
this.map.setFilter(
|
||||||
|
LAYERS.BUILDING_HIGHLIGHT.id,
|
||||||
|
layerFilterEq(hoveredId),
|
||||||
|
);
|
||||||
|
this.map.getCanvas().style.cursor = "pointer";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/services/ui-service.ts
Normal file
37
src/services/ui-service.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// LIBRARIES
|
||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
|
// PROJECT
|
||||||
|
import { SelectedFeature } from "@/types/types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for managing UI updates and DOM manipulation
|
||||||
|
*/
|
||||||
|
export class UIService {
|
||||||
|
public $info: JQuery;
|
||||||
|
public $lnglat: JQuery;
|
||||||
|
public $selected: JQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new UIService instance and initializes jQuery selectors
|
||||||
|
*/
|
||||||
|
public constructor() {
|
||||||
|
this.$info = $("#layer");
|
||||||
|
this.$lnglat = $("#lnglat");
|
||||||
|
this.$selected = $("#selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the selected features list in the UI
|
||||||
|
* @param selected - Array of selected features to display
|
||||||
|
*/
|
||||||
|
public updateSelectedList(selected: SelectedFeature[]) {
|
||||||
|
const selectedList = $("<ul>");
|
||||||
|
selected.forEach((feature) => {
|
||||||
|
selectedList.append(
|
||||||
|
`<li>${feature.id} (${feature.area} m<sup>2</sup>)</li>`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
this.$selected.empty().append(selectedList);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Represents a route calculated by the routing service
|
||||||
|
*/
|
||||||
export interface Route {
|
export interface Route {
|
||||||
code: string;
|
code: string;
|
||||||
routes: RouteElement[];
|
routes: RouteElement[];
|
||||||
waypoints: Waypoint[];
|
waypoints: Waypoint[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single route option in the routing response
|
||||||
|
*/
|
||||||
export interface RouteElement {
|
export interface RouteElement {
|
||||||
legs: Leg[];
|
legs: Leg[];
|
||||||
weight_name: string;
|
weight_name: string;
|
||||||
@@ -13,11 +19,17 @@ export interface RouteElement {
|
|||||||
distance: number;
|
distance: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GeoJSON geometry representation
|
||||||
|
*/
|
||||||
export interface Geometry {
|
export interface Geometry {
|
||||||
coordinates: Array<number[]>;
|
coordinates: Array<number[]>;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a leg of a route between two waypoints
|
||||||
|
*/
|
||||||
export interface Leg {
|
export interface Leg {
|
||||||
steps: Step[];
|
steps: Step[];
|
||||||
weight: number;
|
weight: number;
|
||||||
@@ -26,6 +38,9 @@ export interface Leg {
|
|||||||
distance: number;
|
distance: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single step in navigation instructions
|
||||||
|
*/
|
||||||
export interface Step {
|
export interface Step {
|
||||||
intersections: Intersection[];
|
intersections: Intersection[];
|
||||||
driving_side: string;
|
driving_side: string;
|
||||||
@@ -38,6 +53,9 @@ export interface Step {
|
|||||||
distance: number;
|
distance: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an intersection point in the route
|
||||||
|
*/
|
||||||
export interface Intersection {
|
export interface Intersection {
|
||||||
out?: number;
|
out?: number;
|
||||||
entry: boolean[];
|
entry: boolean[];
|
||||||
@@ -46,6 +64,9 @@ export interface Intersection {
|
|||||||
in?: number;
|
in?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a maneuver instruction at a specific location
|
||||||
|
*/
|
||||||
export interface Maneuver {
|
export interface Maneuver {
|
||||||
bearing_after: number;
|
bearing_after: number;
|
||||||
bearing_before: number;
|
bearing_before: number;
|
||||||
@@ -54,9 +75,20 @@ export interface Maneuver {
|
|||||||
modifier?: string;
|
modifier?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a waypoint in the route
|
||||||
|
*/
|
||||||
export interface Waypoint {
|
export interface Waypoint {
|
||||||
hint: string;
|
hint: string;
|
||||||
location: number[];
|
location: number[];
|
||||||
name: string;
|
name: string;
|
||||||
distance: number;
|
distance: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a feature selected on the map
|
||||||
|
*/
|
||||||
|
export interface SelectedFeature {
|
||||||
|
id: number;
|
||||||
|
area: number;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ export const panToCurrentLocation = (map: Map) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a route between two points using the specified transport mode
|
||||||
|
* @param transport - The transport mode to use for routing
|
||||||
|
* @param from - Starting coordinate in "lng,lat" format
|
||||||
|
* @param to - Ending coordinate in "lng,lat" format
|
||||||
|
* @returns A Promise that resolves to the route information
|
||||||
|
* @throws Error if the routing API request fails
|
||||||
|
*/
|
||||||
export const route = async (
|
export const route = async (
|
||||||
transport: Transport,
|
transport: Transport,
|
||||||
from: string,
|
from: string,
|
||||||
|
|||||||
19
src/utilities/layers.ts
Normal file
19
src/utilities/layers.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { FilterSpecification } from "@maptiler/sdk";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an equality filter for Mapbox layer filtering
|
||||||
|
* @param id - The feature ID to match
|
||||||
|
* @returns A FilterSpecification for the given ID
|
||||||
|
*/
|
||||||
|
export const layerFilterEq = (id?: string | number) => {
|
||||||
|
return ["==", ["id"], id ? id : ""] as FilterSpecification;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an inclusion filter for multiple feature IDs
|
||||||
|
* @param ids - Array of feature IDs to include in the filter
|
||||||
|
* @returns A FilterSpecification for the given IDs
|
||||||
|
*/
|
||||||
|
export const layerFilterIn = (ids: Array<string | number | undefined>) => {
|
||||||
|
return ["in", ["id"], ["literal", ids]] as FilterSpecification;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user