Improve selection panel and hub card compass
All checks were successful
Build Docker Image / build (push) Successful in 4m44s
All checks were successful
Build Docker Image / build (push) Successful in 4m44s
This commit is contained in:
@@ -16,16 +16,29 @@
|
||||
]"
|
||||
>
|
||||
<div class="flex flex-col gap-1">
|
||||
<!-- Title -->
|
||||
<Text size="base" weight="semibold" class="truncate">{{ hub.name }}</Text>
|
||||
<!-- Country left, distance right -->
|
||||
<!-- Title + distance/compass -->
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<Text size="base" weight="semibold" class="truncate">{{ hub.name }}</Text>
|
||||
<div class="flex items-center gap-2 text-xs text-white/70 whitespace-nowrap">
|
||||
<Text v-if="distanceLabel" size="xs" class="text-white/70">{{ distanceLabel }}</Text>
|
||||
<div v-if="bearing !== null" class="flex items-center gap-1">
|
||||
<div class="w-6 h-6 rounded-full border border-white/20 bg-white/5 flex items-center justify-center">
|
||||
<Icon
|
||||
name="lucide:arrow-up"
|
||||
size="12"
|
||||
class="text-white/80"
|
||||
:style="{ transform: `rotate(${bearing}deg)` }"
|
||||
/>
|
||||
</div>
|
||||
<Text size="xs" class="text-white/60">{{ Math.round(bearing) }}°</Text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Country -->
|
||||
<div class="flex items-center justify-between">
|
||||
<Text tone="muted" size="sm">
|
||||
{{ countryFlag }} {{ hub.country || t('catalogMap.labels.country_unknown') }}
|
||||
</Text>
|
||||
<span v-if="distanceLabel" class="badge badge-neutral badge-dash text-xs">
|
||||
{{ distanceLabel }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Transport icons bottom -->
|
||||
<div v-if="hub.transportTypes?.length" class="flex items-center gap-1 pt-1">
|
||||
@@ -47,6 +60,8 @@ interface Hub {
|
||||
name?: string | null
|
||||
country?: string | null
|
||||
countryCode?: string | null
|
||||
latitude?: number | null
|
||||
longitude?: number | null
|
||||
distance?: string
|
||||
distanceKm?: number | null
|
||||
transportTypes?: (string | null)[] | null
|
||||
@@ -54,6 +69,7 @@ interface Hub {
|
||||
|
||||
const props = defineProps<{
|
||||
hub: Hub
|
||||
origin?: { latitude: number; longitude: number } | null
|
||||
selectable?: boolean
|
||||
isSelected?: boolean
|
||||
linkTo?: string
|
||||
@@ -88,4 +104,27 @@ const distanceLabel = computed(() => {
|
||||
if (props.hub.distanceKm != null) return `${Math.round(props.hub.distanceKm)} km`
|
||||
return ''
|
||||
})
|
||||
|
||||
const toRadians = (deg: number) => (deg * Math.PI) / 180
|
||||
const toDegrees = (rad: number) => (rad * 180) / Math.PI
|
||||
|
||||
const bearing = computed(() => {
|
||||
const origin = props.origin
|
||||
const lat2 = props.hub.latitude
|
||||
const lon2 = props.hub.longitude
|
||||
if (!origin || lat2 == null || lon2 == null) return null
|
||||
const lat1 = origin.latitude
|
||||
const lon1 = origin.longitude
|
||||
if (lat1 == null || lon1 == null) return null
|
||||
|
||||
const φ1 = toRadians(lat1)
|
||||
const φ2 = toRadians(lat2)
|
||||
const Δλ = toRadians(lon2 - lon1)
|
||||
|
||||
const y = Math.sin(Δλ) * Math.cos(φ2)
|
||||
const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(Δλ)
|
||||
const θ = Math.atan2(y, x)
|
||||
const deg = (toDegrees(θ) + 360) % 360
|
||||
return deg
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user