postgres DAL + New UI
This commit is contained in:
@@ -1,6 +1,4 @@
|
|||||||
// ------------------------------
|
|
||||||
// MAP SETUP
|
|
||||||
// ------------------------------
|
|
||||||
var streets = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
var streets = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
attribution: '© OpenStreetMap contributors'
|
attribution: '© OpenStreetMap contributors'
|
||||||
});
|
});
|
||||||
@@ -23,10 +21,6 @@ const MJR_LINES = ["701", "703", "704", "720", "750"];
|
|||||||
const LRT_LINES = ["701", "703", "704", "720"];
|
const LRT_LINES = ["701", "703", "704", "720"];
|
||||||
const FRONTRUNNER = ["750"];
|
const FRONTRUNNER = ["750"];
|
||||||
const API_URL = "http://localhost:7653/api/v0/";
|
const API_URL = "http://localhost:7653/api/v0/";
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// ROUTE STYLES
|
|
||||||
// ------------------------------
|
|
||||||
const ROUTE_STYLES = {
|
const ROUTE_STYLES = {
|
||||||
"701": { color: "#0074D9", train: "🔵", stop: "🔹" },
|
"701": { color: "#0074D9", train: "🔵", stop: "🔹" },
|
||||||
"704": { color: "#2ECC40", train: "🟢", stop: "🟩" },
|
"704": { color: "#2ECC40", train: "🟢", stop: "🟩" },
|
||||||
@@ -35,11 +29,8 @@ const ROUTE_STYLES = {
|
|||||||
"720": { color: "#000000", train: "⚪", stop: "🔷" }
|
"720": { color: "#000000", train: "⚪", stop: "🔷" }
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// ICON BUILDER
|
|
||||||
// ------------------------------
|
|
||||||
function buildIcon(emoji, bearing) {
|
function buildIcon(emoji, bearing) {
|
||||||
const rotate = bearing ? `transform: rotate(${bearing}deg); transform-origin: center;` : '';
|
|
||||||
const svg = `
|
const svg = `
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
|
||||||
<text x="50%" y="50%" text-anchor="middle"
|
<text x="50%" y="50%" text-anchor="middle"
|
||||||
@@ -59,9 +50,6 @@ function buildIcon(emoji, bearing) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// MARKER HELPER
|
|
||||||
// ------------------------------
|
|
||||||
function addMarker(lat, lon, content, icon) {
|
function addMarker(lat, lon, content, icon) {
|
||||||
if (!isNaN(lat) && !isNaN(lon)) {
|
if (!isNaN(lat) && !isNaN(lon)) {
|
||||||
const marker = L.marker([lat, lon], { icon });
|
const marker = L.marker([lat, lon], { icon });
|
||||||
@@ -71,9 +59,7 @@ function addMarker(lat, lon, content, icon) {
|
|||||||
console.warn("Invalid coordinates:", lat, lon);
|
console.warn("Invalid coordinates:", lat, lon);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// ROUTE LINES
|
|
||||||
// ------------------------------
|
|
||||||
function drawPolyLine(polylinePoints, color) {
|
function drawPolyLine(polylinePoints, color) {
|
||||||
L.polyline(polylinePoints, { color, weight: 4, opacity: 0.8 }).addTo(map);
|
L.polyline(polylinePoints, { color, weight: 4, opacity: 0.8 }).addTo(map);
|
||||||
}
|
}
|
||||||
@@ -108,9 +94,7 @@ function drawLines() {
|
|||||||
MJR_LINES.forEach(drawLine);
|
MJR_LINES.forEach(drawLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// STOPS
|
|
||||||
// ------------------------------
|
|
||||||
let stopMarkers = {};
|
let stopMarkers = {};
|
||||||
function getStopsByRoute(route) {
|
function getStopsByRoute(route) {
|
||||||
if (stopMarkers[route]) return;
|
if (stopMarkers[route]) return;
|
||||||
@@ -134,9 +118,6 @@ function getStopsByRoute(route) {
|
|||||||
.catch(err => console.error("Error fetching stops:", err));
|
.catch(err => console.error("Error fetching stops:", err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// VEHICLES
|
|
||||||
// ------------------------------
|
|
||||||
let trainMarkers = {};
|
let trainMarkers = {};
|
||||||
let filterType = "all";
|
let filterType = "all";
|
||||||
|
|
||||||
@@ -153,14 +134,12 @@ function refreshVehicles() {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
let vehicles = data.data;
|
let vehicles = data.data;
|
||||||
|
|
||||||
// Apply filter
|
|
||||||
if (filterType === "lrt") {
|
if (filterType === "lrt") {
|
||||||
vehicles = vehicles.filter(v => LRT_LINES.includes(v.routeNum) || FRONTRUNNER.includes(v.routeNum));
|
vehicles = vehicles.filter(v => LRT_LINES.includes(v.routeNum) || FRONTRUNNER.includes(v.routeNum));
|
||||||
}
|
}
|
||||||
|
|
||||||
vehicles = vehicles.filter(v => MJR_LINES.includes(v.routeNum));
|
vehicles = vehicles.filter(v => MJR_LINES.includes(v.routeNum));
|
||||||
|
|
||||||
// Remove vehicles no longer active
|
|
||||||
Object.keys(trainMarkers).forEach(id => {
|
Object.keys(trainMarkers).forEach(id => {
|
||||||
if (!vehicles.find(v => v.vehicleId == id)) {
|
if (!vehicles.find(v => v.vehicleId == id)) {
|
||||||
map.removeLayer(trainMarkers[id]);
|
map.removeLayer(trainMarkers[id]);
|
||||||
@@ -194,9 +173,7 @@ function refreshVehicles() {
|
|||||||
.catch(err => console.error("Error refreshing vehicles:", err));
|
.catch(err => console.error("Error refreshing vehicles:", err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// USER LOCATION & TRAIN DETECTION
|
|
||||||
// ------------------------------
|
|
||||||
let userMarker, accuracyCircle;
|
let userMarker, accuracyCircle;
|
||||||
const ON_BOARD_RADIUS = 50; // meters
|
const ON_BOARD_RADIUS = 50; // meters
|
||||||
|
|
||||||
@@ -237,7 +214,6 @@ if (navigator.geolocation) {
|
|||||||
if (userMarker) userMarker.setLatLng([userLat, userLon]);
|
if (userMarker) userMarker.setLatLng([userLat, userLon]);
|
||||||
if (accuracyCircle) accuracyCircle.setLatLng([userLat, userLon]).setRadius(position.coords.accuracy);
|
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);
|
const vehicles = Object.values(trainMarkers).map(m => m.vehicleData);
|
||||||
let closest = null, minDistance = Infinity;
|
let closest = null, minDistance = Infinity;
|
||||||
|
|
||||||
@@ -260,9 +236,6 @@ if (navigator.geolocation) {
|
|||||||
console.warn("Geolocation not supported by this browser.");
|
console.warn("Geolocation not supported by this browser.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// INITIAL LOAD
|
|
||||||
// ------------------------------
|
|
||||||
drawLines();
|
drawLines();
|
||||||
MJR_LINES.forEach(r => getStopsByRoute(r));
|
MJR_LINES.forEach(r => getStopsByRoute(r));
|
||||||
refreshVehicles();
|
refreshVehicles();
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// src/dal/postgresdal.js
|
|
||||||
import pg from "pg";
|
import pg from "pg";
|
||||||
|
|
||||||
const pool = new pg.Pool({
|
const pool = new pg.Pool({
|
||||||
@@ -20,7 +19,6 @@ function toNumber(v) {
|
|||||||
return Number.isFinite(n) ? n : undefined;
|
return Number.isFinite(n) ? n : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Vehicles */
|
|
||||||
|
|
||||||
export async function getVehicles() {
|
export async function getVehicles() {
|
||||||
const rows = await dbQuery(
|
const rows = await dbQuery(
|
||||||
@@ -71,7 +69,6 @@ export async function getVehicleById(id) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Routes */
|
|
||||||
|
|
||||||
export async function getRoutes() {
|
export async function getRoutes() {
|
||||||
const rows = await dbQuery(`SELECT data FROM routes ORDER BY route_id`);
|
const rows = await dbQuery(`SELECT data FROM routes ORDER BY route_id`);
|
||||||
@@ -89,7 +86,6 @@ export async function getRouteById(routeId) {
|
|||||||
return rows[0]?.data || null;
|
return rows[0]?.data || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Route paths */
|
|
||||||
|
|
||||||
export async function getRoutePathsMap() {
|
export async function getRoutePathsMap() {
|
||||||
const rows = await dbQuery(`SELECT route_id, path FROM route_paths`);
|
const rows = await dbQuery(`SELECT route_id, path FROM route_paths`);
|
||||||
@@ -111,7 +107,6 @@ export async function getRoutePath(routeId) {
|
|||||||
return rows[0]?.path || null;
|
return rows[0]?.path || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stations */
|
|
||||||
|
|
||||||
function transformationStationRow(row) {
|
function transformationStationRow(row) {
|
||||||
return {
|
return {
|
||||||
@@ -131,7 +126,6 @@ function transformationStationRow(row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getStationsRaw() {
|
export async function getStationsRaw() {
|
||||||
// For compatibility, just return the full array of normalized station rows.
|
|
||||||
const rows = await dbQuery(`SELECT * FROM stations`);
|
const rows = await dbQuery(`SELECT * FROM stations`);
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
@@ -143,7 +137,6 @@ export async function getStations() {
|
|||||||
|
|
||||||
export async function getStopsByRoute(routeId) {
|
export async function getStopsByRoute(routeId) {
|
||||||
if (routeId == null) return [];
|
if (routeId == null) return [];
|
||||||
// lines @> ARRAY[$1]::text[] means: lines contains this value
|
|
||||||
const rows = await dbQuery(
|
const rows = await dbQuery(
|
||||||
`SELECT * FROM stations WHERE lines @> ARRAY[$1]::text[]`,
|
`SELECT * FROM stations WHERE lines @> ARRAY[$1]::text[]`,
|
||||||
[String(routeId)]
|
[String(routeId)]
|
||||||
@@ -163,3 +156,4 @@ export async function getStationById(id) {
|
|||||||
return transformationStationRow(rows[0]);
|
return transformationStationRow(rows[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user