160 lines
4.4 KiB
Vue
160 lines
4.4 KiB
Vue
<template>
|
|
<ClientOnly>
|
|
<mgl-geo-json-source source-id="clusters" :data="clusters">
|
|
<mgl-circle-layer
|
|
layer-id="clusters_dots"
|
|
:paint="cluster_paint"
|
|
@click="clusterClick"
|
|
@mouseenter="clusterEnter"
|
|
@mouseleave="clusterLeave"
|
|
/>
|
|
|
|
<MglSymbolLayer
|
|
layer-id="cluster_icon"
|
|
:layout="{
|
|
'icon-image': 'cluster',
|
|
'icon-size': 0.1,
|
|
'icon-overlap': 'always',
|
|
'text-overlap': 'always',
|
|
}"
|
|
@mouseenter="clusterEnter"
|
|
@mouseleave="clusterLeave"
|
|
/>
|
|
<MglSymbolLayer
|
|
layer-id="clusters_labels"
|
|
:layout="cluster_label"
|
|
/>
|
|
</mgl-geo-json-source>
|
|
|
|
<div ref="popup-div">
|
|
<div v-for="data in popupData" :key="data.pattern.id">
|
|
Direction {{ data.pattern.lastStopName }}
|
|
<div v-for="time in data.times" :key="time.tripId">
|
|
{{
|
|
stopTimeToRealTime(
|
|
time.realtimeArrival,
|
|
time.serviceDay,
|
|
)
|
|
}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ClientOnly>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { FeatureCollection, Point } from "geojson";
|
|
import { useMap } from "@indoorequal/vue-maplibre-gl";
|
|
import { Popup } from "maplibre-gl";
|
|
|
|
const cluster_label = {
|
|
"text-field": ["get", "name"],
|
|
};
|
|
const map = useMap("main");
|
|
const popupDiv = useTemplateRef("popup-div");
|
|
|
|
const { clusters, route } = defineProps<{
|
|
clusters: FeatureCollection<Point>;
|
|
route: Route;
|
|
}>();
|
|
|
|
const cluster_paint = {
|
|
"circle-radius": 18,
|
|
"circle-color": "#" + route.color,
|
|
};
|
|
|
|
const popupData = ref<StopTimesPattern[]>([]);
|
|
const popup = new Popup().setMaxWidth("500px").addTo(map.map!);
|
|
const router = useRoute();
|
|
const store = useMresoStore();
|
|
|
|
onUnmounted(() => {
|
|
popup.off("close", closePopupEventHandler);
|
|
popup.remove();
|
|
});
|
|
|
|
watch(
|
|
() => router.params.cluster_id,
|
|
async () => {
|
|
popup.off("close", closePopupEventHandler);
|
|
await routerParamChange();
|
|
popup.on("close", closePopupEventHandler);
|
|
},
|
|
{ immediate: true },
|
|
);
|
|
|
|
async function clusterClick(e: FeatureCollection) {
|
|
popup.off("close", closePopupEventHandler);
|
|
const feature = e.features[0];
|
|
if (!feature || !feature.properties) {
|
|
return;
|
|
}
|
|
const code = feature.properties.code;
|
|
if (!code) {
|
|
return;
|
|
}
|
|
console.log(code);
|
|
navigateTo(`/lines/${router.params.line_id}/cluster/${code}`);
|
|
popup.remove();
|
|
popup.on("close", closePopupEventHandler);
|
|
}
|
|
|
|
async function routerParamChange() {
|
|
if (router.params.cluster_id === undefined) {
|
|
popup.remove();
|
|
return;
|
|
}
|
|
if (typeof router.params.cluster_id !== "string") {
|
|
return;
|
|
}
|
|
const cluster = store.clustersByCode[router.params.cluster_id];
|
|
if (!cluster) {
|
|
return;
|
|
}
|
|
const code = cluster.properties?.code;
|
|
if (!code) {
|
|
return;
|
|
}
|
|
popupData.value = [];
|
|
|
|
const coordinates = cluster.geometry.coordinates.slice();
|
|
|
|
popupData.value = await $fetch<StopTimesPattern[]>(
|
|
`https://data.mobilites-m.fr/api/routers/default/index/clusters/${code}/stoptimes?showCancelledTrips=false&route=${route.id}`,
|
|
{
|
|
headers: {
|
|
origin: "PersonalProjectMreso",
|
|
},
|
|
},
|
|
);
|
|
if (!popupDiv.value) {
|
|
return;
|
|
}
|
|
popup.setDOMContent(popupDiv.value).setLngLat(coordinates).addTo(map.map!);
|
|
}
|
|
|
|
function closePopupEventHandler() {
|
|
navigateTo(`/lines/${router.params.line_id}`);
|
|
}
|
|
|
|
function stopTimeToRealTime(realtimeArrival: number, serviceDay: number) {
|
|
const seconds =
|
|
realtimeArrival -
|
|
(Math.floor(new Date().getTime() / 1000) - serviceDay);
|
|
if (seconds < 0) {
|
|
return "00:00:00";
|
|
}
|
|
const date = new Date(0);
|
|
date.setSeconds(seconds); // specify value for SECONDS here
|
|
const timeString = date.toISOString().substring(11, 19);
|
|
return timeString;
|
|
}
|
|
|
|
function clusterEnter() {
|
|
map.map!.getCanvas().style.cursor = "pointer";
|
|
}
|
|
function clusterLeave() {
|
|
map.map!.getCanvas().style.cursor = "";
|
|
}
|
|
</script>
|