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); 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({ export const realtimeRouter = createTRPCRouter({
coordinates: protectedProcedure coordinates: protectedProcedure
.input(z.object({ projectId: z.string() })) .input(z.object({ projectId: z.string() }))
.query(async ({ input }) => { .query(async ({ input }) => {
const res = await chQuery<{ const res = await chQuery<CoordinatePoint>(
city: string;
country: string;
long: number;
lat: number;
count: number;
}>(
`SELECT `SELECT
country, country,
city, city,
@@ -129,13 +189,11 @@ export const realtimeRouter = createTRPCRouter({
AND longitude IS NOT NULL AND longitude IS NOT NULL
AND latitude IS NOT NULL AND latitude IS NOT NULL
GROUP BY country, city, longitude, latitude GROUP BY country, city, longitude, latitude
ORDER BY count DESC` ORDER BY count DESC
LIMIT 5000`
); );
res.forEach((item) => { return adaptiveCluster(res, 500);
console.log(item.country, item.city, item.long, item.lat);
});
return res;
}), }),
mapBadgeDetails: protectedProcedure mapBadgeDetails: protectedProcedure
.input( .input(