next-show-radar

License Dependencies Peer API key

Try it live - the hosted demo, geolocation prompt and all.

The geolocation-aware tour map from The DJ Calendar, extracted as a standalone, open-source widget. Give it a list of shows; it shows the visitor the ones near them - and stays useful when they decline.

What actually happens (the plain-English version)

When a page uses this widget, the browser itself pops up a small question near the address bar:

“this-site.com wants to know your location. Allow / Block”

That prompt is the whole game, and the widget is built around both answers:

The visitor taps Allow. The browser hands the page a latitude and longitude. The radar draws a red “You are here” dot at that spot, measures the real distance to every show pin, and zooms to fit the ones within 200 miles. The caption under the map reads: “4 shows within 200 miles.” The visitor instantly knows the DJ is playing 20 minutes from them on June 6.

The visitor taps Block. The browser hands the page nothing - no coordinates at all. This is where most map widgets fail: the code crashes, or the map renders as a blank gray rectangle, or it just sits there. The radar does none of that. It quietly falls back to the useful experience it always had in it: every show pin on a global map, zoomed to fit, with the caption “Location not available - showing all 24 shows.”

That second case matters more than the first. A lot of people tap Block on location prompts - they are right to be cautious. On most sites those visitors get a broken or useless map. Here they get the same working map everyone else does, minus only the personalization. The map is never the hero. The shows are - and no answer to the permission prompt ever breaks them.

The live demo lets you see both experiences back to back: allow the prompt once, then click “Reset location memory” and reload to be asked again and block it.

The design stance

Geolocation on most sites is a checkbox: a permission prompt bolted onto a map that collapses when denied. The radar’s stance is that “no” is a first-class answer.

Quick start

<link rel="stylesheet" href="leaflet.css">
<link rel="stylesheet" href="src/radar.css">
<script src="src/radar.js" defer></script>

<div data-radar
     data-radar-points='[{"lat":40.759,"lng":-73.9845,"title":"Alan Walker","venue":"Marquee New York","city":"New York City, NY","date":"Jun 6","url":"https://..."}]'>
</div>

Dynamic markup? Call the manual API after insertion:

NextShowRadar.init(container, { radius: 60, color: "#3fb950" });

The data contract

One JSON array, injected into the page - server-rendered or set at runtime. No fetch, no API keys, no backend contract beyond JSON:

[
  {
    "lat": 40.759,
    "lng": -73.9845,
    "title": "Alan Walker",
    "venue": "Marquee New York",
    "city": "New York City, NY",
    "date": "Jun 6",
    "url": "https://example.com/tickets"
  }
]

Points without numeric lat/lng are silently omitted. An un-geocoded show must never become a pin at 0,0 in the South Atlantic.

Knobs

Knob data attribute options key Default
Nearby radius (miles) data-radar-radius radius 200
Fallback zoom (empty radius) data-radar-fallback-zoom fallbackZoom 8
Pin color data-radar-color color #00d2ff
Tile URL template data-radar-tiles tiles Esri Dark Gray
Tile native max zoom data-radar-max-zoom maxNativeZoom 16

Tiles & providers (why the default changed)

The widget ships with Esri’s keyless dark-gray canvas as its default basemap, and that default is a deliberate engineering decision rather than a taste call. CARTO’s public basemap CDN served free, keyless raster tiles for years, and this widget originally defaulted to their beautiful Dark Matter style - but in 2026 CARTO began gating keyless traffic, and maps that defaulted to those URLs started rendering error tiles reading “API key required.”

A widget whose default map silently breaks is a widget nobody can trust, so the default is now a provider that works today with no account: Esri’s World Dark Gray canvas (free with attribution, which the widget supplies).

Accessibility

The status caption is a real role="status" / aria-live="polite" region, and it is visible - sighted users and screen readers get the same sentence, not a hidden one-off transcript. Every outcome is announced: nearby count, empty radius, denial, and no-data. prefers-reduced-motion turns off the pan/zoom animations; the map simply arrives where it means to be.

Race safety

The boot is guarded: a render flag prevents double-initialization, init retries on DOMContentLoaded and window.load, and the engine polls briefly for the Leaflet peer before rendering - and announces clearly if it never arrives. The production version of this loader logic survived a real bug class - duplicated library injection destroying an initialized map - which is documented in its sibling repo, sri-lazy-loader.

The pair

On The DJ Calendar, sri-lazy-loader brings Leaflet in safely - one tag, SRI-verified, race-free - and next-show-radar is the reason that loader needed to exist. Use them together, or use this with any Leaflet you already trust.

Requirements

Origin

Extracted from The DJ Calendar (https://thedjcalendar.com), where the radar pattern centers the tour map on every visitor who opts in. Like everything published under this account, it is a production-derived pattern: what ships here is the idea, not the infrastructure.

License

MIT