163 lines
4.4 KiB
Vue
163 lines
4.4 KiB
Vue
<template>
|
|
<ClientOnly>
|
|
<MglMap :map-style="style" :center="center" :zoom="zoom" height="100%">
|
|
<MglNavigationControl />
|
|
<MapLines
|
|
v-for="r of routeWithLines"
|
|
:key="r.route.id"
|
|
:route-with-line="r"
|
|
/>
|
|
<MapClusters
|
|
v-if="clustersData.features"
|
|
:clusters="clustersData"
|
|
/>
|
|
</MglMap>
|
|
</ClientOnly>
|
|
|
|
<div v-if="routesRequest.data.value" id="lineSelector">
|
|
<div
|
|
v-for="route of routesRequest.data.value"
|
|
:key="route.id"
|
|
:class="{
|
|
selected: selectedRoutes.includes(route.id),
|
|
lineLabel: true,
|
|
}"
|
|
:style="{
|
|
background: '#' + route.color,
|
|
color: '#' + route.textColor,
|
|
}"
|
|
@click="selectRoute(route.id)"
|
|
>
|
|
{{ route.type }} : {{ route.shortName }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type {
|
|
Feature,
|
|
FeatureCollection,
|
|
MultiLineString,
|
|
Point,
|
|
} from "geojson";
|
|
import { useMap } from "@indoorequal/vue-maplibre-gl";
|
|
import { LngLat, LngLatBounds } from "maplibre-gl";
|
|
const style = "https://tiles.versatiles.org/assets/styles/colorful/style.json";
|
|
const center = new LngLat(5.735, 45.185);
|
|
const zoom = 12;
|
|
|
|
const map = useMap();
|
|
|
|
const selectedRoutes = ref<string[]>([]);
|
|
const selectedStops = ref<string[]>([]);
|
|
|
|
const clustersRequest =
|
|
await useFetch<FeatureCollection<Point>>("/clusters.json");
|
|
const clusters = computed(() => clustersRequest.data.value?.features ?? []);
|
|
const clustersData = computed<FeatureCollection<Point>>(() => {
|
|
return {
|
|
type: "FeatureCollection",
|
|
features: clusters.value.filter((f) =>
|
|
selectedStops.value.includes(f.properties?.id),
|
|
),
|
|
};
|
|
});
|
|
|
|
const linesRequest =
|
|
await useFetch<FeatureCollection<MultiLineString>>("/lignes.json");
|
|
const transport_lines = computed(() => linesRequest.data.value?.features ?? []);
|
|
|
|
const routesRequest = await useFetch<Route[]>("/routes.json");
|
|
|
|
// Selected routes with lines
|
|
const routeWithLines = computed(() => {
|
|
const shownLines: { route: Route; line: Feature<MultiLineString> }[] = [];
|
|
for (const routeId of selectedRoutes.value) {
|
|
const route = routesRequest.data.value?.find((r) => r.id == routeId);
|
|
if (!route) {
|
|
continue;
|
|
}
|
|
const line = transport_lines.value.find(
|
|
(f) => routeId == f.properties?.id.replace("_", ":"),
|
|
);
|
|
if (!line) {
|
|
continue;
|
|
}
|
|
shownLines.push({
|
|
route,
|
|
line,
|
|
});
|
|
}
|
|
return shownLines;
|
|
});
|
|
|
|
async function selectRoute(routeId: string) {
|
|
if (!map.map) {
|
|
console.error("Map is not yet initialized ! aborting");
|
|
return;
|
|
}
|
|
selectedRoutes.value = [routeId];
|
|
const stops: string[] = [];
|
|
for (const route of selectedRoutes.value) {
|
|
const data = await $fetch<Cluster[]>(
|
|
`https://data.mobilites-m.fr/api/routers/default/index/routes/${route.replace("_", ":")}/clusters`,
|
|
);
|
|
|
|
for (const stop of data) {
|
|
stops.push(stop.id);
|
|
}
|
|
}
|
|
|
|
selectedStops.value = stops;
|
|
|
|
const points = clusters.value.filter((c) =>
|
|
stops.includes(c.properties?.id),
|
|
);
|
|
const firstPoint = points[0];
|
|
if (!firstPoint) {
|
|
console.error("Data does not contains any points. Aborting");
|
|
return;
|
|
}
|
|
const bounds = clusters.value
|
|
.filter((c) => stops.includes(c.properties?.id))
|
|
.reduce(
|
|
(bounds, point) => {
|
|
return bounds.extend(
|
|
new LngLat(
|
|
point.geometry.coordinates[0]!,
|
|
point.geometry.coordinates[1]!,
|
|
),
|
|
);
|
|
},
|
|
new LngLatBounds([
|
|
firstPoint.geometry.coordinates[0]!,
|
|
firstPoint.geometry.coordinates[1]!,
|
|
firstPoint.geometry.coordinates[0]!,
|
|
firstPoint.geometry.coordinates[1]!,
|
|
]),
|
|
);
|
|
|
|
map.map.fitBounds(bounds, {
|
|
padding: 20,
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="css">
|
|
#lineSelector {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
height: 100vh;
|
|
overflow: auto;
|
|
background: white;
|
|
}
|
|
|
|
.lineLabel {
|
|
cursor: pointer;
|
|
}
|
|
.lineLabel.selected {
|
|
color: red !important;
|
|
}
|
|
</style>
|