This commit is contained in:
Matteo Rosati
2026-01-23 15:41:20 +01:00
commit bc5edbc1cb
7 changed files with 2625 additions and 0 deletions

40
src/layers.ts Normal file
View File

@@ -0,0 +1,40 @@
import { FillLayerSpecification, LineLayerSpecification } from "@maptiler/sdk";
export const LAYERS = {
BUILDING_HIGHLIGHT: {
id: "building-highlight",
type: "fill",
source: "buildings",
"source-layer": "building",
paint: {
"fill-color": "#4fba45",
"fill-opacity": 1,
},
filter: ["==", ["id"], ""],
} as FillLayerSpecification,
BUILDING_SELECT: {
id: "building-select",
type: "fill",
source: "buildings",
"source-layer": "building",
paint: {
"fill-color": "#8e289c",
"fill-opacity": 1,
},
filter: ["==", ["id"], ""],
} 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,
};

47
src/main.css Normal file
View File

@@ -0,0 +1,47 @@
body,
html {
margin: 0;
padding: 0;
font-family: "monospaced";
}
body {
font-family: "JetBrains Mono Variable", monospace;
}
#info {
z-index: 500;
position: fixed;
top: 10px;
right: 10px;
width: 400px;
height: calc((100vh) - 30px);
border-radius: 8px;
background-color: rgba(0, 0, 0, 0.85);
padding: 5px;
}
.info-box {
margin: 10px;
padding: 10px;
color: #fff;
border: 1px solid green;
}
.info-box .title {
margin-top: 5px;
font-weight: bold;
background: rgba(0, 255, 0, 0.3);
padding: 8px;
}
.info-box ul {
margin-bottom: 0;
padding-left: 25px;
}
.info-box li {
}
#map {
height: 100vh;
}

120
src/main.ts Normal file
View File

@@ -0,0 +1,120 @@
import "@fontsource-variable/jetbrains-mono";
import "./main.css";
import "@maptiler/sdk/dist/maptiler-sdk.css";
import $ from "jquery";
import {
ExpressionSpecificationDefinition,
FilterSpecification,
Map,
config,
} from "@maptiler/sdk";
import { LAYERS } from "./layers";
const MAP_STYLE = "019be805-c88e-7c8b-9850-bc704d72e604";
const API_KEY = "8nmgHEIZQiIgqQj3RZNa";
const INITIAL_ZOOM = 17;
config.apiKey = API_KEY;
const $info = $("#layer");
const $lnglat = $("#lnglat");
const $selected = $("#selected");
let selected: Array<string | number | undefined> = [];
const map = new Map({
container: "map",
style: MAP_STYLE,
});
// Funzione helper per settare i filtri dei layer.
// 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);
// console.log(map.getLayer("road_network")?.source);
// console.log(map.getLayer("road_network")?.sourceLayer);
// console.log(map.getLayer("road_network")?.paint);
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} ${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());
}
});
map.on("click", (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ["building_matteo"],
});
if (features && features.length > 0) {
const clicked = features[0];
const clickedId = clicked.id;
if (!selected.includes(clickedId)) {
selected.push(clickedId);
} else {
selected.splice(selected.indexOf(clickedId), 1);
}
const selectedList = $("<ul>");
selected.forEach((id) => {
selectedList.append(`<li>${id}</li>`);
});
$selected.empty().append(selectedList);
if (selected.length === 0) {
$selected.append("<div>None</div>");
}
if (clickedId) {
map.setFilter(LAYERS.BUILDING_HIGHLIGHT.id, layerFilterEq());
map.setFilter(LAYERS.BUILDING_SELECT.id, layerFilterIn(selected));
map.getCanvas().style.cursor = "pointer";
}
} else {
map.getCanvas().style.cursor = "default";
}
});
});
navigator.geolocation.getCurrentPosition((position) => {
map.setZoom(INITIAL_ZOOM);
map.panTo({
lat: position.coords.latitude,
lng: position.coords.longitude,
});
});