-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
114 lines (97 loc) · 3.54 KB
/
script.js
File metadata and controls
114 lines (97 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// script.js (FULL) — UCDP events.json -> Leaflet map with clustering
// --- Map init ---
const map = L.map("map").setView([31.5, 39.0], 5);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: '© OpenStreetMap contributors',
}).addTo(map);
// --- Marker clustering (requires Leaflet.markercluster plugin) ---
const markers = L.markerClusterGroup({
// Tweaks for performance/UX
chunkedLoading: true,
chunkInterval: 200,
chunkDelay: 50,
removeOutsideVisibleBounds: true,
});
// --- Helper: color by severity ---
function colorForFatalities(f) {
if (f >= 25) return "red";
if (f >= 10) return "orange";
if (f >= 2) return "yellow";
return "gray";
}
// --- Helper: safe text ---
function esc(s) {
return String(s ?? "")
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
// --- Load events ---
fetch("events.json", { cache: "no-store" })
.then((r) => {
if (!r.ok) throw new Error(`HTTP ${r.status} loading events.json`);
return r.json();
})
.then((events) => {
if (!Array.isArray(events)) throw new Error("events.json is not an array");
let plotted = 0;
events.forEach((e) => {
const lat = Number(e.lat);
const lng = Number(e.lng);
if (!Number.isFinite(lat) || !Number.isFinite(lng)) return;
const fatalities = Number(e.fatalities) || 0;
const actor1 = esc(e.actor1);
const actor2 = esc(e.actor2);
const date = esc(e.date);
const country = esc(e.country);
const location = esc(e.location);
const source = esc(e.source);
const sourceDate = esc(e.source_date);
const headline = esc(e.headline);
const searchUrl =
"https://www.google.com/search?q=" +
encodeURIComponent((e.headline || "").toString());
// Use circleMarker for visual severity; wrap in a DivIcon marker for clustering.
// MarkerCluster works with L.Marker, so we create a tiny "dot" marker using DivIcon.
const color = colorForFatalities(fatalities);
const icon = L.divIcon({
className: "event-dot",
html: `<div style="
width:10px;height:10px;border-radius:50%;
background:${color};
border:2px solid ${color};
opacity:0.85;"></div>`,
iconSize: [10, 10],
iconAnchor: [5, 5],
});
const m = L.marker([lat, lng], { icon });
m.bindPopup(`
<div style="min-width:240px">
<div><b>${actor1} vs ${actor2}</b></div>
<div><b>Fatalities:</b> ${fatalities}</div>
<div><b>Date:</b> ${date}</div>
<div><b>Country:</b> ${country}</div>
<div><b>Location:</b> ${location}</div>
<hr style="margin:8px 0">
<div><b>Source:</b> ${source}</div>
<div><b>Source date:</b> ${sourceDate}</div>
<div style="margin-top:6px"><i>"${headline}"</i></div>
<div style="margin-top:8px">
<a href="${searchUrl}" target="_blank" rel="noopener noreferrer">
Search headline for verification
</a>
</div>
</div>
`);
markers.addLayer(m);
plotted++;
});
map.addLayer(markers);
console.log(`Loaded ${events.length} events; plotted ${plotted}.`);
})
.catch((err) => {
console.error("Error loading events:", err);
alert("Error loading events.json. Check console for details.");
});