Added concentric donut charts and added an alliance breakdown
This commit is contained in:
@@ -89,32 +89,51 @@ export function getFlightsPerDay(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
|
||||
// ── Grouping helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
function groupByName(flights: Flight[], accessor: (f: Flight) => string) {
|
||||
const counts = new Map<string, number>()
|
||||
flights.forEach(f => {
|
||||
const key = accessor(f) ?? 'Unknown'
|
||||
counts.set(key, (counts.get(key) ?? 0) + 1)
|
||||
})
|
||||
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1])
|
||||
function groupByNameSplit(flights: Flight[], upcomingFlights: Flight[], accessor: (f: Flight) => string) {
|
||||
const countOne = (list: Flight[]) => {
|
||||
const counts = new Map<string, number>()
|
||||
list.forEach(f => {
|
||||
const key = accessor(f) ?? 'Unknown'
|
||||
counts.set(key, (counts.get(key) ?? 0) + 1)
|
||||
})
|
||||
return counts
|
||||
}
|
||||
|
||||
const past = countOne(flights)
|
||||
const upcoming = countOne(upcomingFlights)
|
||||
const allNames = new Set([...past.keys(), ...upcoming.keys()])
|
||||
|
||||
const sorted = [...allNames]
|
||||
.map(name => ({
|
||||
name,
|
||||
past: past.get(name) ?? 0,
|
||||
upcoming: upcoming.get(name) ?? 0,
|
||||
}))
|
||||
.sort((a, b) => (b.past + b.upcoming) - (a.past + a.upcoming))
|
||||
|
||||
return {
|
||||
labels: sorted.map(([name]) => name),
|
||||
series: sorted.map(([, count]) => count),
|
||||
labels: sorted.map(s => s.name),
|
||||
series: [
|
||||
{ name: 'Flown', data: sorted.map(s => s.past) },
|
||||
{ name: 'Upcoming', data: sorted.map(s => s.upcoming) },
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
export function getFlightReasons(flights: Flight[]) {
|
||||
const result = groupByName(flights, f => f.flight_reason?.name ?? 'Unknown')
|
||||
return result
|
||||
export function getFlightReasons(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
return groupByNameSplit(flights, upcomingFlights, f => f.flight_reason?.name ?? 'Unknown')
|
||||
}
|
||||
|
||||
export function getFlightClasses(flights: Flight[]) {
|
||||
const result = groupByName(flights, f => f.flight_class?.name ?? 'Unknown')
|
||||
return result
|
||||
export function getFlightClasses(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
return groupByNameSplit(flights, upcomingFlights, f => f.flight_class?.name ?? 'Unknown')
|
||||
}
|
||||
|
||||
export function getSeatTypes(flights: Flight[]) {
|
||||
const result = groupByName(flights, f => f.seat_type?.name ?? 'Unknown')
|
||||
return result
|
||||
export function getSeatTypes(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
return groupByNameSplit(flights, upcomingFlights, f => f.seat_type?.name ?? 'Unknown')
|
||||
}
|
||||
|
||||
export function getAlliances(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
return groupByNameSplit(flights, upcomingFlights, f => f.airline?.alliance?.name ?? 'No Alliance')
|
||||
}
|
||||
|
||||
// ── Countries ─────────────────────────────────────────────────────────────────
|
||||
@@ -156,7 +175,7 @@ export function getCountries(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
const result = {
|
||||
countries: sorted,
|
||||
series: [
|
||||
{ name: 'Flights', data: sorted.map(s => s.past) },
|
||||
{ name: 'Departed', data: sorted.map(s => s.past) },
|
||||
{ name: 'Upcoming', data: sorted.map(s => s.upcoming) },
|
||||
],
|
||||
}
|
||||
@@ -165,7 +184,7 @@ export function getCountries(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
|
||||
// ── Continents ────────────────────────────────────────────────────────────────
|
||||
|
||||
export function getContinents(flights: Flight[]) {
|
||||
function countContinents(flights: Flight[]) {
|
||||
const counts = new Map<string, number>()
|
||||
flights.forEach(f => {
|
||||
const continents = new Set<string>()
|
||||
@@ -175,10 +194,28 @@ export function getContinents(flights: Flight[]) {
|
||||
if (arr) continents.add(arr)
|
||||
continents.forEach(c => counts.set(c, (counts.get(c) ?? 0) + 1))
|
||||
})
|
||||
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1])
|
||||
return counts
|
||||
}
|
||||
|
||||
export function getContinents(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
const past = countContinents(flights)
|
||||
const upcoming = countContinents(upcomingFlights)
|
||||
const allNames = new Set([...past.keys(), ...upcoming.keys()])
|
||||
|
||||
const sorted = [...allNames]
|
||||
.map(name => ({
|
||||
name,
|
||||
past: past.get(name) ?? 0,
|
||||
upcoming: upcoming.get(name) ?? 0,
|
||||
}))
|
||||
.sort((a, b) => (b.past + b.upcoming) - (a.past + a.upcoming))
|
||||
|
||||
const result = {
|
||||
labels: sorted.map(([name]) => name),
|
||||
series: sorted.map(([, count]) => count),
|
||||
labels: sorted.map(s => s.name),
|
||||
series: [
|
||||
{ name: 'Flown', data: sorted.map(s => s.past) },
|
||||
{ name: 'Upcoming', data: sorted.map(s => s.upcoming) },
|
||||
],
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -215,7 +252,7 @@ export function getTopAirlines(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
const result = {
|
||||
airlines: sorted,
|
||||
series: [
|
||||
{ name: 'Flights', data: sorted.map(s => s.past) },
|
||||
{ name: 'Flown', data: sorted.map(s => s.past) },
|
||||
{ name: 'Upcoming', data: sorted.map(s => s.upcoming) },
|
||||
],
|
||||
}
|
||||
@@ -338,7 +375,7 @@ export function getTopAircraft(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
const result = {
|
||||
aircraft: sorted,
|
||||
series: [
|
||||
{ name: 'Flights', data: sorted.map(s => s.past) },
|
||||
{ name: 'Flown', data: sorted.map(s => s.past) },
|
||||
{ name: 'Upcoming', data: sorted.map(s => s.upcoming) },
|
||||
],
|
||||
}
|
||||
@@ -391,7 +428,7 @@ export function getTopRoutes(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
const result = {
|
||||
routes: sorted,
|
||||
series: [
|
||||
{ name: 'Flights', data: sorted.map(s => s.past) },
|
||||
{ name: 'Flown', data: sorted.map(s => s.past) },
|
||||
{ name: 'Upcoming', data: sorted.map(s => s.upcoming) },
|
||||
],
|
||||
}
|
||||
@@ -400,7 +437,7 @@ export function getTopRoutes(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
|
||||
// ── Flight types ──────────────────────────────────────────────────────────────
|
||||
|
||||
export function getFlightTypes(flights: Flight[]) {
|
||||
function countFlightTypes(flights: Flight[]) {
|
||||
const counts = { International: 0, Domestic: 0 }
|
||||
flights.forEach(f => {
|
||||
const dep = f.departure_airport.region?.country?.id
|
||||
@@ -409,10 +446,22 @@ export function getFlightTypes(flights: Flight[]) {
|
||||
dep === arr ? counts.Domestic++ : counts.International++
|
||||
}
|
||||
})
|
||||
const sorted = Object.entries(counts).filter(([, count]) => count > 0)
|
||||
return counts
|
||||
}
|
||||
|
||||
export function getFlightTypes(flights: Flight[], upcomingFlights: Flight[]) {
|
||||
const past = countFlightTypes(flights)
|
||||
const upcoming = countFlightTypes(upcomingFlights)
|
||||
|
||||
const names = ['International', 'Domestic'] as const
|
||||
const relevant = names.filter(name => past[name] > 0 || upcoming[name] > 0)
|
||||
|
||||
const result = {
|
||||
labels: sorted.map(([name]) => name),
|
||||
series: sorted.map(([, count]) => count),
|
||||
labels: relevant,
|
||||
series: [
|
||||
{ name: 'Flown', data: relevant.map(name => past[name]) },
|
||||
{ name: 'Upcoming', data: relevant.map(name => upcoming[name]) },
|
||||
],
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -443,16 +492,17 @@ export function useFlightStats(flights: Ref<Flight[]>) {
|
||||
const perYear = computed(() => getFlightsPerYear(pastFlights.value, upcomingFlights.value))
|
||||
const perMonth = computed(() => getFlightsPerMonth(pastFlights.value, upcomingFlights.value))
|
||||
const perDay = computed(() => getFlightsPerDay(pastFlights.value, upcomingFlights.value))
|
||||
const reasons = computed(() => getFlightReasons(allFlights.value))
|
||||
const classes = computed(() => getFlightClasses(allFlights.value))
|
||||
const seatTypes = computed(() => getSeatTypes(allFlights.value))
|
||||
const reasons = computed(() => getFlightReasons(pastFlights.value, upcomingFlights.value))
|
||||
const classes = computed(() => getFlightClasses(pastFlights.value, upcomingFlights.value))
|
||||
const seatTypes = computed(() => getSeatTypes(pastFlights.value, upcomingFlights.value))
|
||||
const alliances = computed(() => getAlliances(pastFlights.value, upcomingFlights.value))
|
||||
const countries = computed(() => getCountries(pastFlights.value, upcomingFlights.value))
|
||||
const continents = computed(() => getContinents(allFlights.value))
|
||||
const continents = computed(() => getContinents(pastFlights.value, upcomingFlights.value))
|
||||
const topAirlines = computed(() => getTopAirlines(pastFlights.value, upcomingFlights.value))
|
||||
const topAirports = computed(() => getTopAirports(pastFlights.value, upcomingFlights.value))
|
||||
const topAircraft = computed(() => getTopAircraft(pastFlights.value, upcomingFlights.value))
|
||||
const topRoutes = computed(() => getTopRoutes(pastFlights.value, upcomingFlights.value))
|
||||
const flightTypes = computed(() => getFlightTypes(allFlights.value))
|
||||
const flightTypes = computed(() => getFlightTypes(pastFlights.value, upcomingFlights.value))
|
||||
|
||||
return {
|
||||
pastFlights,
|
||||
@@ -463,6 +513,7 @@ export function useFlightStats(flights: Ref<Flight[]>) {
|
||||
reasons,
|
||||
classes,
|
||||
seatTypes,
|
||||
alliances,
|
||||
countries,
|
||||
continents,
|
||||
flightTypes,
|
||||
|
||||
Reference in New Issue
Block a user