Skip to content

Commit 442fd13

Browse files
committed
so far so ok
1 parent 791b0f4 commit 442fd13

File tree

3 files changed

+139
-18
lines changed

3 files changed

+139
-18
lines changed

src/App.svelte

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
import Map from "./lib/Map.svelte";
44
import SlidingPane from "./lib/SlidingPane.svelte";
55
import { getGeoEntriesInBounds, getUniqueByGeoHash } from "./lib/geodata";
6+
import { updateURLParams, readURLParams } from "./lib/urlState";
67
78
let markers = [];
89
9-
let dataStatus = "not started";
10-
1110
// State to control the sliding pane
1211
let isPaneOpen = false;
1312
let wikiPage = "";
@@ -23,28 +22,38 @@
2322
zoom: 1,
2423
};
2524
25+
// Track if we need to select a marker once data is loaded
26+
2627
// Function to open the pane with a Wikipedia page
2728
function openWikiPane(page) {
2829
wikiPage = page;
2930
isPaneOpen = true;
3031
}
3132
3233
// Function to handle marker clicks
33-
function handleMarkerClick(event) {
34+
async function handleMarkerClick(event) {
3435
const marker = event.detail;
3536
selectedMarker = marker;
36-
37-
// Set the target location instead of directly setting center/zoom
37+
const hashlevel = Math.max(1, Math.min(8, mapZoom / 2));
38+
markers = addMarkerClasses([...markers], hashlevel);
39+
openWikiPane(marker.page_title);
3840
targetMapLocation = {
3941
lat: marker.lat,
4042
lon: marker.lon,
4143
zoom: Math.max(13, mapZoom), // Ensure zoom is at least 13
4244
};
4345
44-
openWikiPane(marker.page_title);
46+
// Update URL only for user-initiated actions
47+
updateURLParams(targetMapLocation, selectedMarker);
4548
}
4649
47-
function addCosmeticsToEntries(entries, hashlevel) {
50+
function addMarkerClasses(entries, hashlevel) {
51+
for (const entry of entries) {
52+
entry.isSelected = selectedMarker
53+
? entry.page_title === selectedMarker.page_title &&
54+
entry.geohash === selectedMarker.geohash
55+
: false;
56+
}
4857
if (hashlevel > 7.5) {
4958
for (const entry of entries) {
5059
entry.sizeClass = "full";
@@ -69,34 +78,70 @@
6978
}
7079
}
7180
// Sort entries so "full" size class appears last
81+
// TODO: probably better done via the CSS classes
7282
entries.sort((a, b) => {
73-
if (a.sizeClass === "full" && b.sizeClass !== "full") return 1;
74-
if (a.sizeClass !== "full" && b.sizeClass === "full") return -1;
83+
if (a.isSelected) {
84+
console.log("here");
85+
return -1;
86+
}
87+
if (a.sizeClass === "full" && b.sizeClass !== "full") return -1;
88+
if (a.sizeClass !== "full" && b.sizeClass === "full") return 1;
7589
return 0;
7690
});
91+
return entries;
7792
}
7893
async function handleBoundsChange(event) {
7994
const center = event.detail.center;
8095
mapZoom = event.detail.zoom;
81-
console.log(event.detail.center);
96+
97+
// Update targetMapLocation with the new center and zoom
98+
const urlTargetMapLocation = {
99+
lat: center.lat,
100+
lon: center.lng,
101+
zoom: mapZoom,
102+
};
103+
updateURLParams(urlTargetMapLocation, selectedMarker);
104+
82105
const bounds = {
83106
minLat: event.detail.bounds._southWest.lat,
84107
maxLat: event.detail.bounds._northEast.lat,
85108
minLon: event.detail.bounds._southWest.lng,
86109
maxLon: event.detail.bounds._northEast.lng,
87110
};
111+
88112
const entries = await getGeoEntriesInBounds(bounds);
89113
const hashlevel = Math.max(1, Math.min(8, mapZoom / 2));
90114
const uniqueEntries = getUniqueByGeoHash({
91115
entries,
92116
hashLength: hashlevel,
93117
scoreField: "page_len",
94118
});
95-
addCosmeticsToEntries(uniqueEntries, hashlevel);
119+
if (
120+
selectedMarker &&
121+
!uniqueEntries.some(
122+
(entry) =>
123+
entry.page_title === selectedMarker.page_title &&
124+
entry.geohash === selectedMarker.geohash
125+
)
126+
) {
127+
uniqueEntries.push(selectedMarker);
128+
}
129+
130+
addMarkerClasses(uniqueEntries, hashlevel);
96131
markers = uniqueEntries;
97132
}
98133
onMount(async () => {
99134
console.log("App starting");
135+
136+
// Read URL parameters when the app loads
137+
const urlState = readURLParams();
138+
if (urlState.targetLocation) {
139+
targetMapLocation = urlState.targetLocation;
140+
}
141+
if (urlState.selectedMarker) {
142+
selectedMarker = urlState.selectedMarker;
143+
openWikiPane(selectedMarker.page_title);
144+
}
100145
});
101146
</script>
102147

src/lib/Map.svelte

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66
77
// Props
88
export let markers = [];
9-
// export let zoom = 13;
10-
// export let center = [51.508056, -0.076111]; // Default to London
11-
export let onMarkerClick = null; // Function to call when marker is clicked
12-
139
// New props for controlled centering
1410
export let targetLocation = null; // Format: { lat, lon, zoom }
1511
@@ -22,6 +18,8 @@
2218
2319
let isFlying = false; // Track if map is currently in flyTo animation
2420
21+
let selectedMarker = null;
22+
2523
function computeMarkerHtml(marker) {
2624
const iconByType = {
2725
adm1st: "map",
@@ -147,9 +145,14 @@
147145
148146
// Watch for changes to targetLocation and update the map view
149147
$: if (map && targetLocation) {
148+
updateMarkers();
150149
flyTo(targetLocation);
151150
}
152151
152+
$: if (markers && map) {
153+
updateMarkers();
154+
}
155+
153156
function handleBoundsChange() {
154157
if (!map || isFlying) return; // Skip if map is flying
155158
@@ -171,6 +174,8 @@
171174
172175
// Add new markers
173176
markers.forEach((marker) => {
177+
// Set isSelected property based on selected marker
178+
174179
const markerHtml = computeMarkerHtml(marker);
175180
const icon = L.divIcon({
176181
className: "custom-div-icon",
@@ -189,9 +194,6 @@
189194
}
190195
191196
// Watch for changes to markers
192-
$: if (markers && map) {
193-
updateMarkers();
194-
}
195197
196198
// Handle container size changes
197199
function handleResize() {
@@ -234,6 +236,12 @@
234236
&.marker-selected > .marker-icon-circle {
235237
--circle-size: 32px !important;
236238
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.35);
239+
z-index: 1000 !important;
240+
}
241+
242+
&.marker-selected {
243+
/* Ensure hovered markers appear above others */
244+
z-index: 1000 !important;
237245
}
238246
239247
&:hover > .marker-text-container,

src/lib/urlState.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Updates the URL with current map state without reloading the page
3+
* @param {Object} targetLocation - The map location {lat, lon, zoom}
4+
* @param {Object|null} selectedMarker - Currently selected marker, if any
5+
*/
6+
export function updateURLParams(targetLocation, selectedMarker) {
7+
const params = new URLSearchParams();
8+
9+
// Add map position parameters
10+
params.set('lat', targetLocation.lat.toFixed(6));
11+
params.set('lon', targetLocation.lon.toFixed(6));
12+
params.set('zoom', targetLocation.zoom.toString());
13+
14+
// Add selected marker as base64-encoded JSON if present
15+
if (selectedMarker) {
16+
try {
17+
const markerJson = JSON.stringify(selectedMarker);
18+
const markerBase64 = btoa(encodeURIComponent(markerJson));
19+
params.set('marker', markerBase64);
20+
} catch (e) {
21+
console.error('Error encoding marker data:', e);
22+
}
23+
}
24+
25+
// Update URL without reloading the page
26+
const newUrl = `${window.location.pathname}?${params.toString()}`;
27+
window.history.replaceState({}, '', newUrl);
28+
}
29+
30+
/**
31+
* Reads map state from URL parameters
32+
* @returns {Object} - Object containing parsed parameters and selected marker
33+
*/
34+
export function readURLParams() {
35+
const params = new URLSearchParams(window.location.search);
36+
37+
// Get map position parameters
38+
const lat = parseFloat(params.get('lat'));
39+
const lon = parseFloat(params.get('lon'));
40+
const zoom = parseInt(params.get('zoom'));
41+
const markerBase64 = params.get('marker');
42+
43+
const result = {
44+
targetLocation: null,
45+
selectedMarker: null
46+
};
47+
48+
// Update location if valid parameters exist
49+
if (!isNaN(lat) && !isNaN(lon) && !isNaN(zoom)) {
50+
result.targetLocation = {
51+
lat,
52+
lon,
53+
zoom
54+
};
55+
}
56+
57+
// If there's a marker parameter, decode the base64 data
58+
if (markerBase64) {
59+
try {
60+
const markerJson = decodeURIComponent(atob(markerBase64));
61+
result.selectedMarker = JSON.parse(markerJson);
62+
} catch (e) {
63+
console.error('Error decoding marker data:', e);
64+
}
65+
}
66+
67+
return result;
68+
}

0 commit comments

Comments
 (0)