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
+85
-48
No files matched your search
@@ -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;
|
||||||
|
|||||||
+79
-48
@@ -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,6 +124,54 @@ protobuf.load("/schema.proto").then((root) => {
|
|||||||
|
|
||||||
let bannerVisible = false
|
let bannerVisible = false
|
||||||
|
|
||||||
|
let currentVehicles = new Map()
|
||||||
|
|
||||||
|
function renderVehicleIcon(vehicle) {
|
||||||
|
return L.divIcon({
|
||||||
|
className: "",
|
||||||
|
html: `<div class="vehicle ${
|
||||||
|
vehicle.route.type == RouteType.BUS &&
|
||||||
|
!["92235", "3686", "87711"].includes(vehicle.route.id)
|
||||||
|
? "vehicle-plain"
|
||||||
|
: ""
|
||||||
|
} ${
|
||||||
|
vehicle.route.type == RouteType.BUS ? "vehicle-small" : ""
|
||||||
|
}" style="--color: #${vehicle.route.color};">
|
||||||
|
<div style="position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;">
|
||||||
|
<svg style="transform: rotate(${
|
||||||
|
vehicle.bearing
|
||||||
|
}deg) translateY(-12px); width: 18px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M300.3 199.2C312.9 188.9 331.4 189.7 343.1 201.4L471.1 329.4C480.3 338.6 483 352.3 478 364.3C473 376.3 461.4 384 448.5 384L192.5 384C179.6 384 167.9 376.2 162.9 364.2C157.9 352.2 160.7 338.5 169.9 329.4L297.9 201.4L300.3 199.2z"/></svg>
|
||||||
|
</div>
|
||||||
|
${
|
||||||
|
vehicle.route.type == RouteType.BUS
|
||||||
|
? ICONS.bus
|
||||||
|
: vehicle.route.type == RouteType.TRAM
|
||||||
|
? ICONS.tram
|
||||||
|
: vehicle.route.type == RouteType.RAIL
|
||||||
|
? ICONS.train
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</div>`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
async function reload() {
|
||||||
const bin = await fetch("/api").then((r) => r.arrayBuffer());
|
const bin = await fetch("/api").then((r) => r.arrayBuffer());
|
||||||
const { vehicles, info } = root
|
const { vehicles, info } = root
|
||||||
@@ -146,59 +196,40 @@ protobuf.load("/schema.proto").then((root) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// render vehicles on map
|
const seenVehicleIds = new Set()
|
||||||
clearMap();
|
|
||||||
|
|
||||||
vehicles.forEach((vehicle) => {
|
vehicles.forEach((vehicle) => {
|
||||||
L.marker([vehicle.lat, vehicle.lon], {
|
seenVehicleIds.add(vehicle.id)
|
||||||
zIndexOffset:
|
|
||||||
vehicle.route.type == RouteType.TRAM ||
|
if (currentVehicles.has(vehicle.id)) { // if this vehicle is already on the map, update its location
|
||||||
vehicle.route.type == RouteType.RAIL
|
currentVehicles.get(vehicle.id).marker.setLatLng([vehicle.lat, vehicle.lon])
|
||||||
? 4000
|
currentVehicles.get(vehicle.id).marker.setIcon(renderVehicleIcon(vehicle))
|
||||||
: 3000,
|
} else {
|
||||||
icon: L.divIcon({
|
const marker = renderVehicle(vehicle)
|
||||||
className: "",
|
marker.addTo(
|
||||||
html: `<div class="vehicle ${
|
|
||||||
vehicle.route.type == RouteType.BUS &&
|
|
||||||
!["92235", "3686", "87711"].includes(vehicle.route.id)
|
|
||||||
? "vehicle-plain"
|
|
||||||
: ""
|
|
||||||
} ${
|
|
||||||
vehicle.route.type == RouteType.BUS ? "vehicle-small" : ""
|
|
||||||
}" style="--color: #${vehicle.route.color};">
|
|
||||||
<div style="position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;">
|
|
||||||
<svg style="transform: rotate(${
|
|
||||||
vehicle.bearing
|
|
||||||
}deg) translateY(-12px); width: 18px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M300.3 199.2C312.9 188.9 331.4 189.7 343.1 201.4L471.1 329.4C480.3 338.6 483 352.3 478 364.3C473 376.3 461.4 384 448.5 384L192.5 384C179.6 384 167.9 376.2 162.9 364.2C157.9 352.2 160.7 338.5 169.9 329.4L297.9 201.4L300.3 199.2z"/></svg>
|
|
||||||
</div>
|
|
||||||
${
|
|
||||||
vehicle.route.type == RouteType.BUS
|
|
||||||
? ICONS.bus
|
|
||||||
: vehicle.route.type == RouteType.TRAM
|
|
||||||
? ICONS.tram
|
|
||||||
: vehicle.route.type == RouteType.RAIL
|
|
||||||
? ICONS.train
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
</div>`,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.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
|
||||||
? traxLayer
|
? traxLayer
|
||||||
: 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();
|
||||||
|
|||||||
Reference in new issue
Block a user