From 2771b5ea74bed4a410296034e6ba0f06ab313d72 Mon Sep 17 00:00:00 2001 From: nspackman Date: Mon, 1 Dec 2025 21:48:05 -0800 Subject: [PATCH] revert eeb63fa51052fb63d0c28657f2bd8a9b5124888c revert Postgres DAL --- public/app.js | 268 ++++------------------------------------- public/index.html | 30 ++--- src/dal/postgresDAL.js | 165 ------------------------- src/routes/routes.js | 6 +- src/routes/vehicles.js | 6 +- 5 files changed, 38 insertions(+), 437 deletions(-) delete mode 100644 src/dal/postgresDAL.js diff --git a/public/app.js b/public/app.js index b3a53b1..d110b19 100644 --- a/public/app.js +++ b/public/app.js @@ -1,269 +1,49 @@ -// ------------------------------ -// MAP SETUP -// ------------------------------ -var streets = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: '© OpenStreetMap contributors' -}); +const map = L.map("map").setView([40.7608, -111.8910], 12); -var satellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/' + - 'World_Imagery/MapServer/tile/{z}/{y}/{x}', { - attribution: 'Tiles © Esri' -}); +L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: '© OpenStreetMap', +}).addTo(map); -var map = L.map('map', { - center: [40.7608, -111.8910], - zoom: 13, - layers: [streets] -}); - -var baseMaps = { "Streets": streets, "Satellite": satellite }; -L.control.layers(baseMaps).addTo(map); - -const MJR_LINES = ["701", "703", "704", "720", "750"]; -const LRT_LINES = ["701", "703", "704", "720"]; -const FRONTRUNNER = ["750"]; const API_URL = "http://localhost:7653/api/v0/"; -// ------------------------------ -// ROUTE STYLES -// ------------------------------ -const ROUTE_STYLES = { - "701": { color: "#0074D9", train: "🔵", stop: "🔹" }, - "704": { color: "#2ECC40", train: "🟢", stop: "🟩" }, - "703": { color: "#FF4136", train: "🔴", stop: "🔺" }, - "750": { color: "#B10DC9", train: "🟣", stop: "🔮" }, - "720": { color: "#000000", train: "⚪", stop: "🔷" } -}; +const trainEmojiIcon = L.divIcon({ html: "🔵", className: "", iconSize: [64,64], iconAnchor: [16,32], popupAnchor: [0,-32] }); +const stopsEmojiIcon = L.divIcon({ html: "🫃", className: "", iconSize: [64,64], iconAnchor: [16,32], popupAnchor: [0,-32] }); -// ------------------------------ -// ICON BUILDER -// ------------------------------ -function buildIcon(emoji, bearing) { - const rotate = bearing ? `transform: rotate(${bearing}deg); transform-origin: center;` : ''; - const svg = ` - - - ${emoji} - - `; - - return L.divIcon({ - html: svg, - className: "emoji-icon", - iconSize: [32, 32], - iconAnchor: [16, 16], - popupAnchor: [0, -16] - }); -} - -// ------------------------------ -// MARKER HELPER -// ------------------------------ function addMarker(lat, lon, content, icon) { if (!isNaN(lat) && !isNaN(lon)) { - const marker = L.marker([lat, lon], { icon }); + const marker = L.marker([lat, lon], { icon: icon }).addTo(map); if (content) marker.bindPopup(content); - return marker; + } else { + console.warn("Invalid coordinates:", latitude, longitude); } - console.warn("Invalid coordinates:", lat, lon); } -// ------------------------------ -// ROUTE LINES -// ------------------------------ -function drawPolyLine(polylinePoints, color) { - L.polyline(polylinePoints, { color, weight: 4, opacity: 0.8 }).addTo(map); -} - -function drawLine(route) { - fetch(API_URL + "routepaths/" + route) +function getTrainsByRoute(route) { + fetch(API_URL + 'vehicles') .then(res => res.json()) .then(data => { - const points = data.data; - if (!points || points.length === 0) return; - const color = ROUTE_STYLES[route].color; - - let polylinePoints = []; - let currentShape = points[0].shape_id; - - points.forEach(p => { - if (p.shape_id === currentShape) { - polylinePoints.push([p.lat, p.lng]); - } else { - drawPolyLine(polylinePoints, color); - polylinePoints = [[p.lat, p.lng]]; - currentShape = p.shape_id; - } + const trains = data.data; + const filtered = route ? trains.filter(t => t.routeId == route) : trains; + filtered.forEach(t => { + addMarker(t.location.latitude, t.location.longitude, t.routeName + ": Vehicle " + t.vehicleId, trainEmojiIcon); }); - - if (polylinePoints.length > 0) drawPolyLine(polylinePoints, color); }) - .catch(err => console.error("Error drawing line:", err)); + .catch(err => console.error("Error fetching trains:", err)); } -function drawLines() { - MJR_LINES.forEach(drawLine); -} - -// ------------------------------ -// STOPS -// ------------------------------ -let stopMarkers = {}; function getStopsByRoute(route) { - if (stopMarkers[route]) return; - stopMarkers[route] = []; - const stopIcon = buildIcon(ROUTE_STYLES[route].stop); - - fetch(API_URL + "stops/" + route) + fetch(API_URL + 'stops/' + route) .then(res => res.json()) .then(data => { - data.data.forEach(s => { - const lat = parseFloat(s.location.latitude); - const lon = parseFloat(s.location.longitude); - const marker = addMarker( - lat, lon, - `${s.stop_name}
${s.stop_desc}`, - stopIcon - ).addTo(map); - stopMarkers[route].push(marker); + const stops = data.data; + stops.forEach(s => { + const lat = parseFloat(s.stop_lat); + const lon = parseFloat(s.stop_lon); + addMarker(lat,lon, s.stop_name + " - " + s.stop_desc, stopsEmojiIcon); }); }) .catch(err => console.error("Error fetching stops:", err)); } -// ------------------------------ -// VEHICLES -// ------------------------------ -let trainMarkers = {}; -let filterType = "all"; - -const filterSelect = document.getElementById("filterSelect"); -if (filterSelect) { - filterSelect.addEventListener("change", (e) => { - filterType = e.target.value; - }); -} - -function refreshVehicles() { - fetch(API_URL + "vehicles") - .then(res => res.json()) - .then(data => { - let vehicles = data.data; - - // Apply filter - if (filterType === "lrt") { - vehicles = vehicles.filter(v => LRT_LINES.includes(v.routeNum) || FRONTRUNNER.includes(v.routeNum)); - } - - vehicles = vehicles.filter(v => MJR_LINES.includes(v.routeNum)); - - // Remove vehicles no longer active - Object.keys(trainMarkers).forEach(id => { - if (!vehicles.find(v => v.vehicleId == id)) { - map.removeLayer(trainMarkers[id]); - delete trainMarkers[id]; - } - }); - - vehicles.forEach(v => { - const { vehicleId, routeNum, routeName, speed, bearing } = v; - const lat = v.location.latitude; - const lon = v.location.longitude; - const icon = buildIcon(ROUTE_STYLES[routeNum].train, bearing); - - if (!trainMarkers[vehicleId]) { - const marker = L.marker([lat, lon], { icon }) - .bindPopup(`${routeName}
Vehicle ${vehicleId}
Speed: ${(speed*2.23694).toFixed(1)} mph`) - .addTo(map); - marker.vehicleData = v; - trainMarkers[vehicleId] = marker; - } else { - if (trainMarkers[vehicleId].slideTo) { - trainMarkers[vehicleId].slideTo([lat, lon], { duration: 1000 }); - } else { - trainMarkers[vehicleId].setLatLng([lat, lon]); - } - trainMarkers[vehicleId].setIcon(icon); - trainMarkers[vehicleId].vehicleData = v; - } - }); - }) - .catch(err => console.error("Error refreshing vehicles:", err)); -} - -// ------------------------------ -// USER LOCATION & TRAIN DETECTION -// ------------------------------ -let userMarker, accuracyCircle; -const ON_BOARD_RADIUS = 50; // meters - -if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition( - (position) => { - const lat = position.coords.latitude; - const lon = position.coords.longitude; - - userMarker = L.circleMarker([lat, lon], { - radius: 8, - fillColor: "#007AFF", - color: "#fff", - weight: 2, - opacity: 1, - fillOpacity: 0.9 - }).addTo(map); - userMarker.bindPopup("You are here").openPopup(); - - accuracyCircle = L.circle([lat, lon], { - radius: position.coords.accuracy, - color: "#007AFF", - fillColor: "#007AFF", - fillOpacity: 0.2 - }).addTo(map); - - map.setView([lat, lon], 13); - }, - (err) => console.warn("Geolocation error:", err.message), - { enableHighAccuracy: true, timeout: 500, maximumAge: 0 } - ); - - navigator.geolocation.watchPosition( - (position) => { - const userLat = position.coords.latitude; - const userLon = position.coords.longitude; - - if (userMarker) userMarker.setLatLng([userLat, userLon]); - if (accuracyCircle) accuracyCircle.setLatLng([userLat, userLon]).setRadius(position.coords.accuracy); - - // Detect if user is on a train - const vehicles = Object.values(trainMarkers).map(m => m.vehicleData); - let closest = null, minDistance = Infinity; - - vehicles.forEach(v => { - const distance = map.distance([userLat, userLon], [v.location.latitude, v.location.longitude]); - if (distance < minDistance) { - minDistance = distance; - closest = v; - } - }); - - if (closest && minDistance <= ON_BOARD_RADIUS) { - console.log(`User is on vehicle ${closest.vehicleId} (${closest.routeNum})`); - } - }, - (err) => console.warn("Geolocation watch error:", err.message), - { enableHighAccuracy: true, maximumAge: 0 } - ); -} else { - console.warn("Geolocation not supported by this browser."); -} - -// ------------------------------ -// INITIAL LOAD -// ------------------------------ -drawLines(); -MJR_LINES.forEach(r => getStopsByRoute(r)); -refreshVehicles(); -setInterval(refreshVehicles, 1000); +getStopsByRoute("701"); +getTrainsByRoute(); diff --git a/public/index.html b/public/index.html index 62de5ee..d9ce6b5 100644 --- a/public/index.html +++ b/public/index.html @@ -1,9 +1,9 @@ - - - Traxer Transit Map + + + Traxer - - - - - -
- - -
- - -
- - - - + +
+ + + diff --git a/src/dal/postgresDAL.js b/src/dal/postgresDAL.js deleted file mode 100644 index 6b0d323..0000000 --- a/src/dal/postgresDAL.js +++ /dev/null @@ -1,165 +0,0 @@ -// src/dal/postgresdal.js -import pg from "pg"; - -const pool = new pg.Pool({ - connectionString: "postgresql://nate@localhost:5432/gtfs" -}); - -async function dbQuery(sql, params = []) { - const client = await pool.connect(); - try { - const res = await client.query(sql, params); - return res.rows; - } finally { - client.release(); - } -} - -function toNumber(v) { - const n = Number(v); - return Number.isFinite(n) ? n : undefined; -} - -/* Vehicles */ - -export async function getVehicles() { - const rows = await dbQuery( - `SELECT vehicle_id, route_num, route_name, destination, - bearing, speed, latitude, longitude - FROM vehicles` - ); - - return rows.map((v) => ({ - vehicleId: v.vehicle_id, - routeNum: v.route_num, - routeName: v.route_name, - destination: v.destination, - bearing: v.bearing == null ? undefined : toNumber(v.bearing), - speed: v.speed == null ? undefined : toNumber(v.speed), - location: { - latitude: toNumber(v.latitude), - longitude: toNumber(v.longitude), - }, - })); -} - -export async function getVehicleById(id) { - if (id == null) return null; - - const rows = await dbQuery( - `SELECT vehicle_id, route_num, route_name, destination, - bearing, speed, latitude, longitude - FROM vehicles - WHERE vehicle_id = $1`, - [String(id)] - ); - - if (!rows.length) return null; - const v = rows[0]; - - return { - vehicleId: v.vehicle_id, - routeNum: v.route_num, - routeName: v.route_name, - destination: v.destination, - bearing: v.bearing == null ? undefined : toNumber(v.bearing), - speed: v.speed == null ? undefined : toNumber(v.speed), - location: { - latitude: toNumber(v.latitude), - longitude: toNumber(v.longitude), - }, - }; -} - -/* Routes */ - -export async function getRoutes() { - const rows = await dbQuery(`SELECT data FROM routes ORDER BY route_id`); - return rows.map((r) => r.data); -} - -export async function getRouteById(routeId) { - if (routeId == null) return null; - - const rows = await dbQuery( - `SELECT data FROM routes WHERE route_id = $1`, - [String(routeId)] - ); - - return rows[0]?.data || null; -} - -/* Route paths */ - -export async function getRoutePathsMap() { - const rows = await dbQuery(`SELECT route_id, path FROM route_paths`); - const map = {}; - for (const row of rows) { - map[String(row.route_id)] = row.path; - } - return map; -} - -export async function getRoutePath(routeId) { - if (routeId == null) return null; - - const rows = await dbQuery( - `SELECT path FROM route_paths WHERE route_id = $1`, - [String(routeId)] - ); - - return rows[0]?.path || null; -} - -/* Stations */ - -function transformationStationRow(row) { - return { - stop_id: row.stop_id, - stop_code: row.stop_code, - stop_name: row.stop_name, - stop_desc: row.stop_desc, - location: { - latitude: toNumber(row.latitude), - longitude: toNumber(row.longitude), - }, - stop_url: row.stop_url, - location_type: row.location_type, - parent_station: row.parent_station, - lines: row.lines, // text[] - }; -} - -export async function getStationsRaw() { - // For compatibility, just return the full array of normalized station rows. - const rows = await dbQuery(`SELECT * FROM stations`); - return rows; -} - -export async function getStations() { - const rows = await dbQuery(`SELECT * FROM stations`); - return rows.map(transformationStationRow); -} - -export async function getStopsByRoute(routeId) { - if (routeId == null) return []; - // lines @> ARRAY[$1]::text[] means: lines contains this value - const rows = await dbQuery( - `SELECT * FROM stations WHERE lines @> ARRAY[$1]::text[]`, - [String(routeId)] - ); - return rows.map(transformationStationRow); -} - -export async function getStationById(id) { - if (id == null) return null; - - const rows = await dbQuery( - `SELECT * FROM stations WHERE stop_id = $1`, - [String(id)] - ); - - if (!rows.length) return null; - return transformationStationRow(rows[0]); -} - diff --git a/src/routes/routes.js b/src/routes/routes.js index 2c3cd19..1dabdd3 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -3,8 +3,8 @@ import * as dal from "../dal/staticDal.js"; const router = express.Router(); -router.get("/routes",async (req, res) => { - const routes = await dal.getRoutes(); +router.get("/routes", (req, res) => { + const routes = dal.getRoutes(); res.json({meta: {returned: routes.length}, data: routes}); }); @@ -47,7 +47,7 @@ router.get("/routes/:routeId/stations", (req, res) => { router.get("/stops/:routeId", (req, res) => { const routeId = req.params.routeId; const stations = dal.getStopsByRoute(routeId); - console.log(stations); + res.json({meta: {routeId: String(routeId), returned: stations.length}, data: stations}); }); diff --git a/src/routes/vehicles.js b/src/routes/vehicles.js index c2b1e15..a43466a 100644 --- a/src/routes/vehicles.js +++ b/src/routes/vehicles.js @@ -1,10 +1,10 @@ import express from "express"; -import * as dal from "../dal/postgresDAL.js"; +import * as dal from "../dal/staticDal.js"; const router = express.Router(); -router.get("/", async (req, res) => { - let vehicles = await dal.getVehicles(); +router.get("/", (req, res) => { + let vehicles = dal.getVehicles(); const {routeNum, routeName, destination, minLat, maxLat, minLng, maxLng, limit} = req.query;