// Leaflet is loaded via CDN in index.html
// @ts-expect-error - Leaflet global
const L = window.L;
export interface MapMarker {
id: string;
lat: number;
lng: number;
label: string;
dreadLevel: number; // 0-3
}
const LOCATIONS: Omit[] = [
{ id: 'rosengard', lat: 55.5894, lng: 13.0414, label: 'Källaren i Rosengård' },
{ id: 'varnhem', lat: 55.5982, lng: 13.0058, label: 'Värnhemstorget' },
{ id: 'torso', lat: 55.6130, lng: 12.9758, label: 'Turning Torso' },
{ id: 'oresund', lat: 55.5789, lng: 12.9200, label: 'Øresundsbron' },
{ id: 'ribersborg',lat: 55.6063, lng: 12.9652, label: 'Ribersborgsstranden' },
{ id: 'davidshall',lat: 55.5963, lng: 13.0021, label: 'Davidshallsgatan' },
{ id: 'stortorget',lat: 55.6047, lng: 13.0038, label: 'Stortorget' },
];
type LeafletMap = ReturnType;
type LeafletMarker = ReturnType;
let map: LeafletMap | null = null;
const markers = new Map();
function dreadColor(level: number): string {
return ['#1a1a2e', '#4a1a4a', '#8b0a8b', '#cc00cc'][Math.min(level, 3)];
}
function dreadRadius(level: number): number {
return [6, 10, 16, 24][Math.min(level, 3)];
}
export function initMap(containerId: string, onClick: (id: string) => void): void {
if (!L) return;
map = L.map(containerId, {
center: [55.597, 13.002],
zoom: 12,
zoomControl: false,
attributionControl: false,
});
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
maxZoom: 18,
}).addTo(map);
for (const loc of LOCATIONS) {
const m = L.circleMarker([loc.lat, loc.lng], {
radius: 6,
color: '#1a1a2e',
fillColor: '#1a1a2e',
fillOpacity: 0.3,
weight: 1,
}).addTo(map).bindTooltip(loc.label, { className: 'map-tooltip', permanent: false });
m.on('click', () => onClick(loc.id));
markers.set(loc.id, m);
}
}
export function updateMap(dread: number, areas: { rosengard: boolean; varnhem: boolean; torso: boolean }): void {
if (!map) return;
const levels: Record = {
rosengard: areas.rosengard ? Math.min(3, Math.floor(dread / 40) + 1) : Math.min(1, Math.floor(dread / 60)),
varnhem: areas.varnhem ? Math.min(3, Math.floor(dread / 35) + 1) : 0,
torso: areas.torso ? 3 : Math.min(1, Math.floor(dread / 80)),
oresund: Math.min(2, Math.floor(dread / 50)),
ribersborg: Math.min(2, Math.floor(dread / 45)),
davidshall: Math.min(1, Math.floor(dread / 70)),
stortorget: Math.min(2, Math.floor(dread / 55)),
};
for (const [id, marker] of markers) {
const level = levels[id] ?? 0;
marker.setStyle({
radius: dreadRadius(level),
color: dreadColor(level),
fillColor: dreadColor(level),
fillOpacity: 0.15 + level * 0.2,
weight: level > 0 ? 2 : 1,
});
}
}