Add per-circuit distance radius support (near: {lat, lon, miles})
Prep for a new circuit that should only show events within 500 miles of St. Louis, MO — the ID given (OlkMrRfxrN) 404s against the leagues endpoint (every other circuit ID is 12 chars, this one is 10, so it's likely missing characters from a copy/paste), so adding the actual circuit entry once that's confirmed. This part is independent and verified against known distances (Collinsville IL ~10mi, Ashland MO ~111mi, PA ~748mi from St. Louis) — a no-op for every existing circuit since `near` is optional and withinRadius() passes everything through when it's unset. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SBzcNkW7JcYipnAX6HfgmK
This commit is contained in:
@@ -41,6 +41,12 @@ loadHTML('/footer.html', 'footer');
|
|||||||
entries here; the page builds one section per circuit.
|
entries here; the page builds one section per circuit.
|
||||||
`id` is the leagueId from a circuit's BCP calendar URL,
|
`id` is the leagueId from a circuit's BCP calendar URL,
|
||||||
e.g. bestcoastpairings.com/circuit/<id>/calendar
|
e.g. bestcoastpairings.com/circuit/<id>/calendar
|
||||||
|
|
||||||
|
Optional `near: { lat, lon, miles }` restricts a circuit to only
|
||||||
|
events within that radius (great-circle distance) — a fixed
|
||||||
|
property of the circuit itself, unlike the Format/Scope toggles
|
||||||
|
which the viewer controls. Events with no coordinate data are
|
||||||
|
excluded rather than assumed to be in range.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
circuits: [
|
circuits: [
|
||||||
@@ -51,6 +57,27 @@ const CONFIG = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// St. Louis, MO — reference point for circuits restricted by distance.
|
||||||
|
const ST_LOUIS = { lat: 38.6270, lon: -90.1994 };
|
||||||
|
|
||||||
|
// Great-circle distance in miles between two lat/lon points (haversine).
|
||||||
|
function milesBetween(lat1, lon1, lat2, lon2) {
|
||||||
|
const R = 3958.8;
|
||||||
|
const toRad = d => (d * Math.PI) / 180;
|
||||||
|
const dLat = toRad(lat2 - lat1);
|
||||||
|
const dLon = toRad(lon2 - lon1);
|
||||||
|
const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
|
||||||
|
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||||
|
}
|
||||||
|
|
||||||
|
function withinRadius(ev, near) {
|
||||||
|
if (!near) return true;
|
||||||
|
const coord = ev.coordinate; // BCP gives [lon, lat]
|
||||||
|
if (!Array.isArray(coord) || coord.length !== 2) return false;
|
||||||
|
const [lon, lat] = coord;
|
||||||
|
return milesBetween(lat, lon, near.lat, near.lon) <= near.miles;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- BCP API ---- */
|
/* ---- BCP API ---- */
|
||||||
const API = "https://newprod-api.bestcoastpairings.com/v1";
|
const API = "https://newprod-api.bestcoastpairings.com/v1";
|
||||||
const HEADERS = { "client-id": "web-app", "env": "bcp", "accept": "application/json" };
|
const HEADERS = { "client-id": "web-app", "env": "bcp", "accept": "application/json" };
|
||||||
@@ -265,7 +292,8 @@ async function load() {
|
|||||||
allResults = await Promise.all(
|
allResults = await Promise.all(
|
||||||
CONFIG.circuits.map(async circuit => {
|
CONFIG.circuits.map(async circuit => {
|
||||||
try {
|
try {
|
||||||
return { circuit, events: await fetchUpcomingEvents(circuit.id) };
|
const events = await fetchUpcomingEvents(circuit.id);
|
||||||
|
return { circuit, events: events.filter(ev => withinRadius(ev, circuit.near)) };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to load circuit", circuit.id, err);
|
console.error("Failed to load circuit", circuit.id, err);
|
||||||
return { circuit, events: [], error: true };
|
return { circuit, events: [], error: true };
|
||||||
|
|||||||
Reference in New Issue
Block a user