fix: improve performance for realtime map

This commit is contained in:
Carl-Gerhard Lindesvärd
2026-03-23 22:31:57 +01:00
parent 2fb993fae5
commit 20665789e1

View File

@@ -106,17 +106,77 @@ function buildRealtimeBadgeDetailsFilter(input: {
return buildRealtimeLocationFilter(input.locations);
}
interface CoordinatePoint {
country: string;
city: string;
long: number;
lat: number;
count: number;
};
function mergeByRadius(
points: CoordinatePoint[],
radius: number
): CoordinatePoint[] {
// Highest-count points become cluster centers; nearby points get absorbed into them
const sorted = [...points].sort((a, b) => b.count - a.count);
const absorbed = new Uint8Array(sorted.length);
const clusters: CoordinatePoint[] = [];
for (let i = 0; i < sorted.length; i++) {
if (absorbed[i]) {
continue;
}
const seed = sorted[i];
if (!seed) {
continue;
}
const center: CoordinatePoint = { ...seed };
for (let j = i + 1; j < sorted.length; j++) {
if (absorbed[j]) {
continue;
}
const other = sorted[j];
if (!other) {
continue;
}
const dlat = other.lat - center.lat;
const dlong = other.long - center.long;
if (Math.sqrt(dlat * dlat + dlong * dlong) <= radius) {
center.count += other.count;
absorbed[j] = 1;
}
}
clusters.push(center);
}
return clusters;
}
function adaptiveCluster(
points: CoordinatePoint[],
target: number
): CoordinatePoint[] {
if (points.length <= target) {
return points;
}
// Expand merge radius until we hit the target (~55km → ~111km → ~333km → ~1110km)
for (const radius of [0.5, 1, 3, 10]) {
const clustered = mergeByRadius(points, radius);
if (clustered.length <= target) {
return clustered;
}
}
return points.slice(0, target);
}
export const realtimeRouter = createTRPCRouter({
coordinates: protectedProcedure
.input(z.object({ projectId: z.string() }))
.query(async ({ input }) => {
const res = await chQuery<{
city: string;
country: string;
long: number;
lat: number;
count: number;
}>(
const res = await chQuery<CoordinatePoint>(
`SELECT
country,
city,
@@ -129,13 +189,11 @@ export const realtimeRouter = createTRPCRouter({
AND longitude IS NOT NULL
AND latitude IS NOT NULL
GROUP BY country, city, longitude, latitude
ORDER BY count DESC`
ORDER BY count DESC
LIMIT 5000`
);
res.forEach((item) => {
console.log(item.country, item.city, item.long, item.lat);
});
return res;
return adaptiveCluster(res, 500);
}),
mapBadgeDetails: protectedProcedure
.input(