One of the pages I'm proudest of on my DJ tour-date site isn't a tour date at all. It's a leaderboard: how many miles each tracked DJ travels between consecutive tour stops, ranked.
The whole thing runs on a JSON file, the haversine formula, and one rule about duplicate venues that looks trivial and isn't. No commercial geo API, no distance-matrix billing, no background jobs. Here's how it works, and the three places the naive version lies to you.
The data
Every artist in my catalog has a tour_dates array. Each gig that can be geo-tagged carries a latitude, a longitude, and a date. Some come in with lat/lng of exactly 0.0, 0.0 - the GPS equivalent of "somewhere."
That's guard-rail number one: a stop at exactly (0.0, 0.0) is not in the ocean southwest of Ghana. It's missing data. Skip it before it drags a route through the Gulf of Guinea.
if ($lat === 0.0 && $lng === 0.0) continue; // null island, not a venue
The distance: haversine, not hype
For the leg between consecutive stops, you can't just subtract coordinates - degrees aren't miles, and straight lines go through the planet. The standard fix is the haversine formula, which computes great-circle distance on a sphere. It's older than the railways, it fits in a handful of lines of PHP, and for tour-routing purposes it's accurate to well under 1%:
$t = deg2rad($q['lat'] - $p['lat']);
$u = deg2rad($q['lng'] - $p['lng']);
$h = sin($t/2) ** 2
+ cos(deg2rad($p['lat'])) * cos(deg2rad($q['lat'])) * sin($u/2) ** 2;
$km += 6371 * 2 * asin(min(1.0, sqrt($h)));
That min(1.0, ...) looks paranoid. It isn't - floating-point jitter can push the haversine term a hair above 1 for near-identical points, and asin of that is NaN. One guard, or the whole leaderboard prints NaN mi and you file a bug report against trigonometry.
Kilometers convert to miles once, at the end, on the total. Round the total, never the legs - rounding per leg compounds error across a thirty-stop tour.
The trap: same venue, next day
Here's where the naive version lies. A DJ plays Friday and Saturday at the same festival. Coordinates: identical. The naive route computes a "leg" of roughly zero miles - fine - but at different venues in the same complex, or venues tagged slightly differently, you get phantom short legs that add up to fake hundreds of miles over a season.
The rule that held up: skip a leg when venue and city both match, case-insensitively, trimmed:
if (strcasecmp(trim($p['venue']), trim($q['venue'])) === 0
&& strcasecmp(trim($p['city']), trim($q['city'])) === 0) { continue; }
Residencies still leak a little, because a venue's own billing changes night to night - but the leaderboard stopped rewarding whichever data pipeline writes venue names most inconsistently. Distance should measure travel, not data noise.
Ordering, legs, and honesty
Stops get sorted chronologically before any math - the route is first city to last city, and the count of legs (actual travel segments, not stops) is what keeps the numbers defensible. An artist with two stops and one leg is a valid row. An artist with too few geo-tagged stops gets skipped, and the skip is counted:
Computed from geo-tagged tour routes; artists with too few geo-tagged stops don't get ranked - and the leaderboard says so.
That sentence is a feature. The fastest way to poison a data project is to quietly fill gaps with guesses. Publish what you measured, count what you skipped, and the journalists who check your methodology find a methodology.
The performance part is boring, on purpose
One JSON file, one pass per artist, one sort per route, done. I haven't needed a caching layer for this yet, and I'd rather ship the honest version and add caching if the data grows than scaffold infrastructure for a leaderboard that fits in memory.
The payoff
The leaderboard is now the hook for my outreach to music-industry press: it carries its own schema (a Dataset, so machines can cite the methodology and not just the page), it lives at thedjcalendar.com/miles, and it answers a question nobody else was answering in public - who actually lives on an airplane?
Total dependencies: zero. Total cost: zero. Total math: one formula you last saw in a navigation textbook and one paranoia guard.
If your favorite DJ's mileage looks wrong - good. Check the venue names. That's usually where the truth leaks.