mirror of
https://github.com/cjdenio/uta-trax-api.git
synced 2026-10-03 16:06:19 +00:00
much new
This commit is contained in:
2 files changed
+81
-44
No files matched your search
@@ -4,6 +4,8 @@
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>UTA Vehicle Tracker</title>
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||
@@ -17,6 +19,10 @@
|
||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
.leaflet-marker-icon:has(.vehicle) {
|
||||
transition: transform 300ms linear;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
|
||||
+75
-44
@@ -1,9 +1,11 @@
|
||||
import * as shapes from "./shapes.js";
|
||||
import protobuf from "https://cdn.jsdelivr.net/npm/protobufjs@8.0.0/dist/protobuf.js/+esm";
|
||||
import * as L from "https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet-src.esm.js";
|
||||
import stations from "./stations.js"
|
||||
import Alpine from "https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/module.esm.min.js";
|
||||
|
||||
import * as shapes from "./shapes.js";
|
||||
import stations from "./stations.js"
|
||||
|
||||
/** @type {number} */
|
||||
let lastUpdated;
|
||||
|
||||
function displayLastUpdated() {
|
||||
@@ -122,41 +124,10 @@ protobuf.load("/schema.proto").then((root) => {
|
||||
|
||||
let bannerVisible = false
|
||||
|
||||
async function reload() {
|
||||
const bin = await fetch("/api").then((r) => r.arrayBuffer());
|
||||
const { vehicles, info } = root
|
||||
.lookupType("VehicleFeed")
|
||||
.decode(new Uint8Array(bin));
|
||||
let currentVehicles = new Map()
|
||||
|
||||
lastUpdated = info.lastUpdate
|
||||
displayLastUpdated()
|
||||
|
||||
populateTotals(vehicles)
|
||||
if (vehicles.length == 0) {
|
||||
if (!bannerVisible) {
|
||||
document.getElementById("banner").classList.remove("hidden")
|
||||
bannerVisible = true
|
||||
map.invalidateSize()
|
||||
}
|
||||
} else {
|
||||
if (bannerVisible) {
|
||||
document.getElementById("banner").classList.add("hidden")
|
||||
bannerVisible = false
|
||||
map.invalidateSize()
|
||||
}
|
||||
}
|
||||
|
||||
// render vehicles on map
|
||||
clearMap();
|
||||
|
||||
vehicles.forEach((vehicle) => {
|
||||
L.marker([vehicle.lat, vehicle.lon], {
|
||||
zIndexOffset:
|
||||
vehicle.route.type == RouteType.TRAM ||
|
||||
vehicle.route.type == RouteType.RAIL
|
||||
? 4000
|
||||
: 3000,
|
||||
icon: L.divIcon({
|
||||
function renderVehicleIcon(vehicle) {
|
||||
return L.divIcon({
|
||||
className: "",
|
||||
html: `<div class="vehicle ${
|
||||
vehicle.route.type == RouteType.BUS &&
|
||||
@@ -181,9 +152,61 @@ protobuf.load("/schema.proto").then((root) => {
|
||||
: ""
|
||||
}
|
||||
</div>`,
|
||||
}),
|
||||
})
|
||||
.addTo(
|
||||
}
|
||||
|
||||
function renderVehicle(vehicle) {
|
||||
return L.marker([vehicle.lat, vehicle.lon], {
|
||||
zIndexOffset:
|
||||
vehicle.route.type == RouteType.TRAM ||
|
||||
vehicle.route.type == RouteType.RAIL
|
||||
? 4000
|
||||
: 3000,
|
||||
icon: renderVehicleIcon(vehicle),
|
||||
})
|
||||
.bindPopup(
|
||||
`<b>${routeDesignator(vehicle.route)}</b> to <b>${vehicle.headsign.replace(
|
||||
/^to /i,
|
||||
""
|
||||
)}</b>${vehicle.nearestStation ? `<br />@ ${vehicle.nearestStation?.name}` : ""}<br /><br /><small>vehicle #: ${vehicle.id}</small>`
|
||||
);
|
||||
}
|
||||
|
||||
async function reload() {
|
||||
const bin = await fetch("/api").then((r) => r.arrayBuffer());
|
||||
const { vehicles, info } = root
|
||||
.lookupType("VehicleFeed")
|
||||
.decode(new Uint8Array(bin));
|
||||
|
||||
lastUpdated = info.lastUpdate
|
||||
displayLastUpdated()
|
||||
|
||||
populateTotals(vehicles)
|
||||
if (vehicles.length == 0) {
|
||||
if (!bannerVisible) {
|
||||
document.getElementById("banner").classList.remove("hidden")
|
||||
bannerVisible = true
|
||||
map.invalidateSize()
|
||||
}
|
||||
} else {
|
||||
if (bannerVisible) {
|
||||
document.getElementById("banner").classList.add("hidden")
|
||||
bannerVisible = false
|
||||
map.invalidateSize()
|
||||
}
|
||||
}
|
||||
|
||||
const seenVehicleIds = new Set()
|
||||
|
||||
vehicles.forEach((vehicle) => {
|
||||
seenVehicleIds.add(vehicle.id)
|
||||
|
||||
if (currentVehicles.has(vehicle.id)) { // if this vehicle is already on the map, update its location
|
||||
currentVehicles.get(vehicle.id).marker.setLatLng([vehicle.lat, vehicle.lon])
|
||||
currentVehicles.get(vehicle.id).marker.setIcon(renderVehicleIcon(vehicle))
|
||||
} else {
|
||||
const marker = renderVehicle(vehicle)
|
||||
marker.addTo(
|
||||
["92235", "3686", "87711"].includes(vehicle.route.id)
|
||||
? brtLayer
|
||||
: vehicle.route.type == RouteType.TRAM
|
||||
@@ -191,14 +214,22 @@ protobuf.load("/schema.proto").then((root) => {
|
||||
: vehicle.route.type == RouteType.RAIL
|
||||
? frontRunnerLayer
|
||||
: busLayer
|
||||
)
|
||||
.bindPopup(
|
||||
`<b>${routeDesignator(vehicle.route)}</b> to <b>${vehicle.headsign.replace(
|
||||
/^to /i,
|
||||
""
|
||||
)}</b>${vehicle.nearestStation ? `<br />@ ${vehicle.nearestStation?.name}` : ""}<br /><br /><small>vehicle #: ${vehicle.id}</small>`
|
||||
);
|
||||
currentVehicles.set(vehicle.id, {
|
||||
vehicle,
|
||||
marker,
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// remove any vehicles that should be removed
|
||||
for (const key of currentVehicles.keys()) {
|
||||
if (!seenVehicleIds.has(key)) {
|
||||
console.log(`removing vehicle from route ${currentVehicles.get(key).vehicle.route.shortName}`)
|
||||
currentVehicles.get(key).marker.remove()
|
||||
currentVehicles.delete(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reload();
|
||||
|
||||
Reference in new issue
Block a user