Files
observable/docs/data/in-n-out-ca-overpass.json.js

119 lines
3.5 KiB
JavaScript

const query = `
[out:json][timeout:120];
area["ISO3166-2"="US-CA"][admin_level=4]->.searchArea;
(
node["amenity"="fast_food"]["brand"="In-N-Out Burger"](area.searchArea);
way["amenity"="fast_food"]["brand"="In-N-Out Burger"](area.searchArea);
relation["amenity"="fast_food"]["brand"="In-N-Out Burger"](area.searchArea);
node["amenity"="fast_food"]["name"~"In-N-Out",i](area.searchArea);
way["amenity"="fast_food"]["name"~"In-N-Out",i](area.searchArea);
relation["amenity"="fast_food"]["name"~"In-N-Out",i](area.searchArea);
);
out center tags;
`;
function normalizeStores(elements) {
const stores = elements
.map((element) => {
const lat = Number(element.lat ?? element.center?.lat);
const lon = Number(element.lon ?? element.center?.lon);
if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
const tags = element.tags ?? {};
const name = tags.name || "In-N-Out Burger";
const city = tags["addr:city"] || "Ville inconnue";
const street = tags["addr:street"] || "";
const housenumber = tags["addr:housenumber"] || "";
const postcode = tags["addr:postcode"] || "";
return {
id: `${element.type}/${element.id}`,
latitude: lat,
longitude: lon,
name,
city,
address: [housenumber, street].filter(Boolean).join(" "),
postcode,
};
})
.filter(Boolean);
const dedup = new Map();
for (const store of stores) {
const key = `${store.latitude.toFixed(5)},${store.longitude.toFixed(5)}`;
if (!dedup.has(key)) dedup.set(key, store);
}
return Array.from(dedup.values());
}
async function fetchFromOverpass() {
const endpoints = [
"https://overpass-api.de/api/interpreter",
"https://overpass.kumi.systems/api/interpreter",
"https://overpass.openstreetmap.fr/api/interpreter",
];
for (const endpoint of endpoints) {
try {
const response = await fetch(endpoint, {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded;charset=UTF-8",
},
body: new URLSearchParams({ data: query }),
});
if (!response.ok) continue;
const payload = await response.json();
const elements = Array.isArray(payload.elements) ? payload.elements : [];
const stores = normalizeStores(elements);
if (stores.length >= 50) return stores;
} catch {}
}
return null;
}
async function fetchFallbackCsv() {
const url =
"https://raw.githubusercontent.com/madmao/castle-compass/master/csv/In%20N%20Out.csv";
const response = await fetch(url);
if (!response.ok)
throw new Error(`Fallback CSV request failed: ${response.status}`);
const lines = (await response.text()).split(/\r?\n/).filter(Boolean);
const stores = lines
.map((line, index) => {
const [latRaw, lonRaw] = line.split(",");
const latitude = Number(latRaw);
const longitude = Number(lonRaw);
if (!Number.isFinite(latitude) || !Number.isFinite(longitude))
return null;
const inCaliforniaBounds =
latitude >= 32 &&
latitude <= 42.5 &&
longitude >= -125 &&
longitude <= -114;
if (!inCaliforniaBounds) return null;
return {
id: `fallback/${index}`,
latitude,
longitude,
name: "In-N-Out Burger",
city: "Ville inconnue",
address: "",
postcode: "",
};
})
.filter(Boolean);
return stores;
}
const stores = (await fetchFromOverpass()) ?? (await fetchFallbackCsv());
process.stdout.write(JSON.stringify(stores));