geohash and message query stuff

This commit is contained in:
2026-06-05 21:09:34 +09:00
parent d5ddff9912
commit 8dcdd7a0e4
6 changed files with 1106 additions and 15 deletions

1059
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,8 @@
"vite": "^8.0.7" "vite": "^8.0.7"
}, },
"dependencies": { "dependencies": {
"@googlemaps/js-api-loader": "^2.1.0" "@googlemaps/js-api-loader": "^2.1.0",
"firebase": "^12.14.0",
"ngeohash": "^0.6.3"
} }
} }

View File

@@ -0,0 +1,16 @@
import { collection, query, where, getDocs } from 'firebase/firestore'; // tools for building and running db queries
import { db } from './config'; // database connection
import { getQueryPrefix } from '$lib/utils/geohash'; // convert coordinates into geohash string
export async function getNearbyMessages(lat, lng) {
const prefix = getQueryPrefix(lat, lng);
const q = query(
collection(db, 'messages'),
where('geohash', '>=', prefix),
where('geohash', '<', prefix + 'z')
);
const snapshot = await getDocs(q);
return snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
}

View File

@@ -5,21 +5,24 @@
// export let latitude; // export let latitude;
// export let longitude; // export let longitude;
// ^ this didn't work for some reason, so instead we get the props like this: (based on internet research this is the fix) // ^ this didn't work for some reason, so instead we get the props like this: (based on internet research this is the fix)
let { latitude, longitude } = $props(); let { lat, lng } = $props();
let mapDiv; // reference ot the map <div> below let mapDiv; // reference ot the map <div> below
onMount (async () => { onMount (async () => {
const centerLat = Number(lat);
const centerLng = Number(lng);
const { setOptions, importLibrary } = await import('@googlemaps/js-api-loader'); const { setOptions, importLibrary } = await import('@googlemaps/js-api-loader');
setOptions({ setOptions({
apiKey: env.PUBLIC_MAPS_KEY, key: env.PUBLIC_MAPS_KEY,
version: 'weekly', version: 'weekly',
}); });
const { Map } = await importLibrary('maps'); const { Map } = await importLibrary('maps');
new Map(mapDiv, { new Map(mapDiv, {
center: { lat: latitude, lng: longitude }, center: { lat: centerLat, lng: centerLng },
zoom: 15, zoom: 15,
disableDefaultUI: true, disableDefaultUI: true,
gestureHandling: 'greedy' gestureHandling: 'greedy'

15
src/lib/utils/geohash.js Normal file
View File

@@ -0,0 +1,15 @@
import ngeohash from 'ngeohash'; // library that does the geohasing encoding/decoding yippee
// encodes the latitude/longitude pair to a 6 character string geohash (~1.2km radius)
export function encode(lat, lng) {
return ngeohash.encode(lat, lng, 6);
}
// encodes a lat/lng pair to a 4 character string geohash (~40km radius) used as a Firestore query prefix
// basically like looking for all geohashes that start with this 4 characters
// it will include all geohashes in a ~40km radius of the given lat/lng pair
// maybe we lessen the radius later but for now is good for testing
export function getQueryPrefix(lat, lng) {
return ngeohash.encode(lat, lng, 4);
}

View File

@@ -2,8 +2,10 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import MapView from '$lib/components/MapView.svelte'; import MapView from '$lib/components/MapView.svelte';
let latitude = $state(); import { getNearbyMessages } from '$lib/firebase/messages.js';
let longitude = $state();
let lat = $state();
let lng = $state();
let error = $state(); let error = $state();
onMount(() => { onMount(() => {
@@ -13,20 +15,22 @@
} }
navigator.geolocation.getCurrentPosition( navigator.geolocation.getCurrentPosition(
(position) => { (position) => {
latitude = position.coords.latitude; lat = position.coords.latitude;
longitude = position.coords.longitude; lng = position.coords.longitude;
}, },
() => { () => {
error = "Location access denied. Please enable location to use Overheard."; error = "Location access denied. Please enable location to use Overheard.";
} }
); );
}); });
</script> </script>
{#if error} {#if error}
<p class="error">{error}</p> <p class="error">{error}</p>
{:else if latitude && longitude} {:else if lat && lng}
<MapView {latitude} {longitude} /> <MapView {lat} {lng} />
{:else} {:else}
<p class="loading">Looking for you...</p> <p class="loading">Looking for you...</p>
{/if} {/if}