vom laptop

This commit is contained in:
2022-12-05 19:04:39 +01:00
parent f3e85c3145
commit dfaa6f6c4c
22 changed files with 24354 additions and 21372 deletions

View File

@ -36,3 +36,98 @@
transform: rotate(360deg);
}
}
.sort-button {
background-color: transparent;
border: none;
padding: 5px 10px;
margin: 0;
line-height: 1;
font-size: 15px;
color: black;
cursor: pointer;
transition: transform 0.05s ease-out;
}
.sort-reverse {
transform: rotate(180deg);
}
table,
th,
td {
border: thin solid;
}
table{
margin: 0 auto;
}
/* Sortable tables */
table.sortable thead {
background-color:rgb(171, 71, 13);
color:#144514;
font-weight: bold;
cursor: default;
}
body{
background-color: rgba(243, 97, 12, 0.31);
}
table,
th,
td
{
background-color: rgba(243, 97, 12, 0.836);
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 5px;
font-size: 1em;
text-align: center;
white-space: nowrap;
}
h1,h2,h4,p
{
text-align: center;
}
.toindex
{
text-align: left;
}
.flexbox
{
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
}
.right
{
width: 100%;
display: flex;
flex-direction: column;
align-items: flex-end;
}
.header
{
border: 0px;
font-weight: 900;
font-size: 2em;
}
.pilot .header
{
font-weight: bold;
}
.link
{
font-size: 80%;
}

View File

@ -1,24 +1,27 @@
import React from 'react';
import './App.css';
import React from "react";
import "./App.css";
import FlightsTable from "./components/FlightsTable";
import SeasonTable from "./components/SeasonTable";
import {groupByMap} from './global/tools';
import flights from './data/HoPe_all_flights.json';
import {IFlight} from './interfaces/IFlights';
import {CSeason} from './classes/CSeason';
function App() {
return (
<div className="App">
<header className="App-header">
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React XXXX
</a>
</header>
</div>
);
const data = flights.data;
const seasondataraw = groupByMap(data, i => i.FKSeason);
const seasondata: CSeason[] = [];
for (let [key, value] of seasondataraw)
{
seasondata.push(new CSeason(key, value));
}
export default App;
export default function App()
{
return(
<div className='App'>
{/* <SeasonTable seasondata = {seasondata} /> */}
<FlightsTable flightdata = {data}/>
</div>
);
}

28
src/classes/CHour.ts Normal file
View File

@ -0,0 +1,28 @@
export class CHour
{
public minutes_sum: number;
private _hours: number;
private _minutes: number;
constructor(secs: number)
{
this.minutes_sum = Math.round(secs / 60);
this._hours = Math.floor(this.minutes_sum / 60);
this._minutes = this.minutes_sum % 60;
}
Add(hour: CHour)
{
this.minutes_sum += hour.minutes_sum;
this._hours = Math.floor(this.minutes_sum / 60);
this._minutes = this.minutes_sum % 60;
}
Print()
{
// const nbspc = String.fromCharCode(160);
// return (nbspc + nbspc + nbspc + this._hours).slice(-4) + ":" + ("0" + this._minutes).slice(-2);
return this._hours + ":" +
("0" + this._minutes).slice(-2);
}
};

31
src/classes/CSeason.ts Normal file
View File

@ -0,0 +1,31 @@
import {IFlight} from '../interfaces/IFlights';
import {CHour} from '../classes/CHour';
export class CSeason
{
id: string;
flighttime: CHour;
flights: IFlight[];
constructor(id: string, flights: IFlight[])
{
this.id = id;
this.flights = flights;
this.flighttime = new CHour(0)
this.calcFlighttime();
}
calcFlighttime()
{
for (let f of this.flights)
{
const ftime: number = +f.FlightDuration;
this.flighttime.Add(new CHour(ftime));
}
}
get flightCount() : number
{
return this.flights.length;
}
}

View File

@ -0,0 +1,42 @@
import React from "react";
import SortableTable from "./SortableTable";
import {THeader} from "./SortableTable";
import {IFlight} from '../interfaces/IFlights';
function Link2Flight(key: string, row: any, data: string | null)
{
var val: JSX.Element = <></>;
const link: string = 'https://de.dhv-xc.de/flight/' + row['IDFlight'];
val = <td><a href={link} target="_blank" rel="noopener noreferrer" >{data}</a></td>;
return val;
}
function Meter2Km(key: string, row: any, data: string | null)
{
var val: JSX.Element = <></>;
const numdata: number = +data! / 1000;
val = <td>{numdata}</td>;
return val;
}
export default function FlightsTable(flightdata: IFlight[])
//export default function FlightsTable(flightdata: any)
{
const headers: THeader[] = [
{ key: "IDFlight", label: "ID", visible: false },
{ key: "FlightDate", label: "Datum", callback: Link2Flight },
{ key: "TakeoffWaypointName", label: "Start" },
{ key: "Glider", label: "Gleitschirm" },
{ key: "BestTaskDistance", label: "Strecke", callback: Meter2Km },
{ key: "BestTaskType", label: "Streckentyp" },
{ key: "BestTaskPoints", label: "Punkte" }
];
return(
<div className='App'>
<SortableTable<IFlight> headers={headers} dataTbl={flightdata} ></SortableTable>
</div>
);
}

View File

@ -0,0 +1,9 @@
import React from "react";
import {CSeason} from '../classes/CSeason';
//export default function SeasonTable(seasondata: CSeason[])
export default function SeasonTable(seasondata: CSeason[])
{
return (<></>);
}

View File

@ -0,0 +1,157 @@
import React from "react";
import { orderBy } from 'natural-orderby';
import { MouseEventHandler, useState } from "react";
export interface ITableTdCallback {(key: string, row: any, data: string | null): JSX.Element};
export type THeader = { key: string; label: string; visible?: boolean; callback?: ITableTdCallback };
type TSortOrder = "ascn" | "desc";
function SortButton({
sortOrder,
columnKey,
sortKey,
onClick,
}: {
sortOrder: TSortOrder;
columnKey: string;
sortKey: string;
onClick: MouseEventHandler<HTMLButtonElement>;
}) {
return (
<button
onClick={onClick}
className={`${
sortKey === columnKey && sortOrder === "desc"
? "sort-button sort-reverse"
: "sort-button"
}`}
>
</button>
);
}
export default function SortableTable<T>({ headers, dataTbl }:
{ headers: THeader[], dataTbl: T[]})
{
const [sortKey, setSortKey] = useState<string>(headers[0].key);
const [sortOrder, setSortOrder] = useState<TSortOrder>("ascn");
const sortedData: T[] = sortData(
{
tableData: dataTbl,
sortKey: sortKey,
reverse: sortOrder === "desc"
});
function changeSort(key: string) {
setSortOrder(sortOrder === "ascn" ? "desc" : "ascn");
setSortKey(key);
}
function sortData({
tableData,
sortKey,
reverse,
}: {
tableData: T[];
sortKey: string;
reverse: boolean;
})
{
if (!sortKey) return tableData;
const order = reverse ? 'asc': 'desc';
// const reval: T[] = orderBy(tableData, [sortKey], [order]);
const reval: T[] = tableData;
return reval;
}
function TableTd({ item, row_item, data } : {item: THeader, row_item: T, data: string | null})
{
var val_complete: JSX.Element = <></>;
if(item.visible === undefined || item.visible === true)
{
if(item.callback)
{
val_complete = item.callback(item.key, row_item, data);
}
else
{
val_complete = (<td>{data}</td>);
}
}
return val_complete;
}
function TableTr(
{headers,row_item}:
{
headers: THeader[],
row_item: T
})
{
return(
<tr>
{
headers.map((h_item) =>
{
var c: any = row_item; // workaround TS2322 TS7053
return ( <TableTd item={h_item} row_item={row_item} data={c[h_item.key]}></TableTd> );
})}
</tr>
);
}
function tableHeader(headers: THeader[])
{
return(
headers.map(
(row) =>
{
if(row.visible === undefined || row.visible === true)
{
return (
<td key={row.key}>
{row.label}{" "}
<SortButton
columnKey={row.key}
onClick={() => changeSort(row.key)}
{...{
sortOrder,
sortKey,
}}
/>
</td>
);
}
else
{
return (<></>);
}
}
));
}
return (
<table className='sortable'>
<thead>
<tr>
{tableHeader(headers)}
</tr>
</thead>
<tbody>
{sortedData.map((row_item) => {
return (
<TableTr headers={headers} row_item = {row_item} />
);
})}
</tbody>
</table>
);
}

1
src/data/HoPe_all_flights.json Executable file

File diff suppressed because one or more lines are too long

8002
src/data/dataX.json Normal file

File diff suppressed because it is too large Load Diff

21
src/global/tools.ts Normal file
View File

@ -0,0 +1,21 @@
export const groupBy = <T, K extends keyof any>(arr: T[], key: (i: T) => K) =>
arr.reduce((groups, item) =>
{
(groups[key(item)] ||= []).push(item);
return groups;
}, {} as Record<K, T[]>);
export function groupByMap<K, V>(list: Array<V>, keyGetter: (input: V) => K): Map<K, Array<V>>
{
const map = new Map<K, Array<V>>();
list.forEach((item) => {
const key = keyGetter(item);
const collection = map.get(key);
if (!collection) {
map.set(key, [item]);
} else {
collection.push(item);
}
});
return map;
}

107
src/interfaces/IFlights.ts Normal file
View File

@ -0,0 +1,107 @@
export interface IFlights {
success: boolean;
message: string;
meta: Meta;
data?: (IFlight)[] | null;
}
export interface Meta {
totalCount: number;
}
export interface IFlight {
IDFlight: string;
FKGliderCategory: string;
Category: string;
FKCompetitionClass: string;
FKCompetitionClassDesired?: null;
CompetitionClass: string;
FKLaunchtype: string;
Launchtype: string;
FKPilot: string;
FirstName: string;
LastName: string;
Nationality: string;
FKFederation?: string | null;
ClubID?: string | null;
ClubName?: string | null;
Glider: string;
FKGlider?: string | null;
FKGliderBrand?: string | null;
GliderBrand?: string | null;
FKGliderClassification: string;
GliderClassification: string;
FKSeason: string;
FlightDate: string;
UtcOffset: string;
FlightStartTime: string;
FlightEndTime: string;
FlightDuration: string;
FirstLat: string;
FirstLng: string;
LastLat: string;
LastLng: string;
FlightMinLat: string;
FlightMaxLat: string;
FlightMinLng: string;
FlightMaxLng: string;
TakeoffCountry: string;
FKTakeoffWaypoint: string;
TakeoffWaypointOffset: string;
TakeoffLocation?: string | null;
TakeoffWaypointName: string;
FKClosestWaypoint?: string | null;
ClosestWaypointOffset?: string | null;
LandingCountry: string;
FKLandingWaypoint?: string | null;
LandingWaypointOffset?: string | null;
LandingWaypointName?: string | null;
LandingLocation?: string | null;
LinearDistance: string;
MaxLinearDistance: string;
ArcDistance?: string | null;
FKBestTaskType: string;
BestTaskType: string;
BestTaskTypeKey: string;
BestTaskDistance: string;
BestTaskPoints: string;
BestTaskDuration: string;
MaxSpeed?: string | null;
GroundSpeed?: string | null;
BestTaskSpeed: string;
TakeoffAltitude: string;
MaxAltitude: string;
MinAltitude: string;
ElevationGain?: string | null;
MeanAltitudeDiff: string;
MaxClimb: string;
MinClimb: string;
Dataversion: string;
ValidBRecordsCount?: string | null;
AirspaceViolationLevel?: string | null;
UserReviewComment: string;
UserReviewStatus: string;
ReviewRequired: string;
ReviewReason: string;
ReviewStatus: string;
ReviewComment: string;
ReviewBy: string;
ReviewTime?: null;
CommentsEnabled: string;
CountComments: string;
HasPhotos: string;
IsBigSmileCandidate: string;
WxcCivlID?: string | null;
WxcNacStatus?: string | null;
WxcSync?: string | null;
WxcSyncTS?: string | null;
IgcFilename: string;
IgcFileHash: string;
GRecordStatus: string;
GValidationMessage: string;
IsNew: string;
CanRetract: string;
StatisticsValid: string;
UC?: string | null;
TC: string;
US: string;
TS: string;
}