This commit is contained in:
cjdenio committed 2026-07-01 21:15:25 -06:00
1 parent 8ac5ceb6f3
commit e7b7285908
2 files changed
+81 -44

No files matched your search

+6
View File
@@ -4,6 +4,8 @@
<html> <html>
<head> <head>
<title>UTA Vehicle Tracker</title>
<link <link
rel="stylesheet" rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" 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"> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet">
<style> <style>
.leaflet-marker-icon:has(.vehicle) {
transition: transform 300ms linear;
}
html, html,
body { body {
margin: 0; margin: 0;
+75 -44
View File
@@ -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 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 * 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 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; let lastUpdated;
function displayLastUpdated() { function displayLastUpdated() {
@@ -122,41 +124,10 @@ protobuf.load("/schema.proto").then((root) => {
let bannerVisible = false let bannerVisible = false
async function reload() { let currentVehicles = new Map()
const bin = await fetch("/api").then((r) => r.arrayBuffer());
const { vehicles, info } = root
.lookupType("VehicleFeed")
.decode(new Uint8Array(bin));
lastUpdated = info.lastUpdate function renderVehicleIcon(vehicle) {
displayLastUpdated() return L.divIcon({
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({
className: "", className: "",
html: `<div class="vehicle ${ html: `<div class="vehicle ${
vehicle.route.type == RouteType.BUS && vehicle.route.type == RouteType.BUS &&
@@ -181,9 +152,61 @@ protobuf.load("/schema.proto").then((root) => {
: "" : ""
} }
</div>`, </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) ["92235", "3686", "87711"].includes(vehicle.route.id)
? brtLayer ? brtLayer
: vehicle.route.type == RouteType.TRAM : vehicle.route.type == RouteType.TRAM
@@ -191,14 +214,22 @@ protobuf.load("/schema.proto").then((root) => {
: vehicle.route.type == RouteType.RAIL : vehicle.route.type == RouteType.RAIL
? frontRunnerLayer ? frontRunnerLayer
: busLayer : 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(); reload();