63 lines
2.2 KiB
TypeScript
63 lines
2.2 KiB
TypeScript
import type { zCoordenadas } from "p-comuns"
|
|
import type z from "zod"
|
|
|
|
export type TipoCoordenadas = z.infer<typeof zCoordenadas>
|
|
|
|
/** Centro padrão do Brasil (Brasília) */
|
|
export const COORDENADAS_PADRAO: TipoCoordenadas = {
|
|
formato: "decimal",
|
|
datum: "EPSG:4326",
|
|
latitude: -15.7801,
|
|
longitude: -47.9292,
|
|
}
|
|
|
|
/** Zoom padrão do mapa */
|
|
export const ZOOM_PADRAO = 4
|
|
|
|
/** Altura padrão do mapa em pixels */
|
|
export const ALTURA_MAPA_PADRAO = 300
|
|
|
|
/** Limites válidos para latitude (-90 a 90) e longitude (-180 a 180) */
|
|
export function coordenadaValida(lat: number, lng: number): boolean {
|
|
return lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180
|
|
}
|
|
|
|
/** Formata número de coordenada para exibição com vírgula (padrão BR) */
|
|
export function formatarCoordenada(valor: number): string {
|
|
return valor.toFixed(6).replace(".", ",")
|
|
}
|
|
|
|
/** Converte texto digitado (aceita vírgula ou ponto) em número. Retorna null se inválido. */
|
|
export function parseCoordenada(v: string | number): number | null {
|
|
if (typeof v === "number") return Number.isNaN(v) ? null : v
|
|
const normalizado = v.replace(",", ".")
|
|
const n = Number.parseFloat(normalizado)
|
|
return Number.isNaN(n) ? null : n
|
|
}
|
|
|
|
/** Tenta geolocalização do navegador; se falhar, usa GeoIP como fallback */
|
|
export async function obterLocalizacao(): Promise<{ latitude: number; longitude: number }> {
|
|
try {
|
|
return await obterViaBrowser()
|
|
} catch {
|
|
return await obterViaGeoIp()
|
|
}
|
|
}
|
|
|
|
function obterViaBrowser(): Promise<{ latitude: number; longitude: number }> {
|
|
return new Promise((resolve, reject) => {
|
|
if (!navigator.geolocation) return reject(new Error("Geolocation indisponível"))
|
|
navigator.geolocation.getCurrentPosition(
|
|
(pos) => resolve({ latitude: pos.coords.latitude, longitude: pos.coords.longitude }),
|
|
(err) => reject(err),
|
|
{ enableHighAccuracy: true, timeout: 10000 },
|
|
)
|
|
})
|
|
}
|
|
|
|
async function obterViaGeoIp(): Promise<{ latitude: number; longitude: number }> {
|
|
const resp = await fetch("https://ipapi.co/json/")
|
|
if (!resp.ok) throw new Error(`GeoIP falhou: ${resp.status}`)
|
|
const dados: { latitude: number; longitude: number } = await resp.json()
|
|
return { latitude: dados.latitude, longitude: dados.longitude }
|
|
}
|