feat: redesign dashboard around place search
This commit is contained in:
66
lib/location-utils.ts
Normal file
66
lib/location-utils.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import type { MeteoStationPosition, SynopStation } from "@/types/imgw";
|
||||
import type { LocationSearchResult, SelectedLocation } from "@/types/location";
|
||||
|
||||
const stationAliases: Record<string, string> = {
|
||||
gdansk: "gdanskrebiechowo",
|
||||
gorzow: "gorzowwielkopolski",
|
||||
katowice: "katowicemuchowiec",
|
||||
kielce: "kielcesukow",
|
||||
kolo: "koloradoszewice",
|
||||
kolobrzeg: "kolobrzegdzwirzyno",
|
||||
krakow: "krakowbalice",
|
||||
lublin: "lublinradawiec",
|
||||
lodz: "lodzlublinek",
|
||||
poznan: "poznanlawica",
|
||||
resko: "reskosmolsko",
|
||||
rzeszow: "rzeszowjasionka",
|
||||
warszawa: "warszawaokecie",
|
||||
};
|
||||
|
||||
function normalizeName(value: string) {
|
||||
return value
|
||||
.replace(/[Łł]/g, "l")
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f]/g, "")
|
||||
.replace(/[^a-zA-Z0-9]/g, "")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
function distanceKm(latitudeA: number, longitudeA: number, latitudeB: number, longitudeB: number) {
|
||||
const earthRadiusKm = 6371;
|
||||
const toRadians = (value: number) => value * Math.PI / 180;
|
||||
const latitudeDistance = toRadians(latitudeB - latitudeA);
|
||||
const longitudeDistance = toRadians(longitudeB - longitudeA);
|
||||
const a = Math.sin(latitudeDistance / 2) ** 2 +
|
||||
Math.cos(toRadians(latitudeA)) * Math.cos(toRadians(latitudeB)) * Math.sin(longitudeDistance / 2) ** 2;
|
||||
return earthRadiusKm * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
}
|
||||
|
||||
export interface LocatedSynopStation extends SynopStation {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
|
||||
export function locateSynopStations(stations: SynopStation[], positions: MeteoStationPosition[]) {
|
||||
const positionsByName = new Map(positions.map((position) => [normalizeName(position.name), position]));
|
||||
return stations.flatMap<LocatedSynopStation>((station) => {
|
||||
const normalizedStation = normalizeName(station.name);
|
||||
const position = positionsByName.get(stationAliases[normalizedStation] ?? normalizedStation);
|
||||
return position ? [{ ...station, latitude: position.latitude, longitude: position.longitude }] : [];
|
||||
});
|
||||
}
|
||||
|
||||
export function findNearestSynopStation(location: LocationSearchResult, stations: LocatedSynopStation[]): SelectedLocation | null {
|
||||
const nearest = stations.reduce<{ station: LocatedSynopStation; distanceKm: number } | null>((best, station) => {
|
||||
const distance = distanceKm(location.latitude, location.longitude, station.latitude, station.longitude);
|
||||
return !best || distance < best.distanceKm ? { station, distanceKm: distance } : best;
|
||||
}, null);
|
||||
if (!nearest) return null;
|
||||
return {
|
||||
name: location.name,
|
||||
province: location.province,
|
||||
stationId: nearest.station.id,
|
||||
stationName: nearest.station.name,
|
||||
distanceKm: Math.round(nearest.distanceKm),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user