Display travels per day and display better marks on the map
This commit is contained in:
parent
1175cc57f5
commit
007da060ed
@ -1,11 +1,19 @@
|
||||
import {useState} from "react"
|
||||
import {useRef, useState} from "react"
|
||||
|
||||
import {Icon} from 'leaflet'
|
||||
import {Polyline, MapContainer, Marker, TileLayer} from 'react-leaflet'
|
||||
|
||||
import './App.css';
|
||||
|
||||
function Map({dep, arr}) {
|
||||
|
||||
function distance(apt1, apt2) {
|
||||
const [lat1, lng1] = [Math.PI * apt1.lat / 180, Math.PI * apt1.lng / 180]
|
||||
const [lat2, lng2] = [Math.PI * apt2.lat / 180, Math.PI * apt2.lng / 180]
|
||||
const a = Math.sin((lat2 - lat1) / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin((lng2 - lng1) / 2) ** 2
|
||||
return (6371 * 2 * Math.atan(Math.sqrt(a) / Math.sqrt(1 - a))).toFixed(0)
|
||||
}
|
||||
|
||||
function Map({mapRef, dep, arr}) {
|
||||
const redIcon = new Icon({
|
||||
iconUrl: "https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png",
|
||||
iconSize: [25, 41],
|
||||
@ -20,50 +28,84 @@ function Map({dep, arr}) {
|
||||
popupAnchor: [1, -34],
|
||||
shadowSize: [41, 41]
|
||||
})
|
||||
|
||||
let depCoords = [dep.lat, dep.lng]
|
||||
let arrCoords = [arr.lat, arr.lng]
|
||||
|
||||
return (
|
||||
<MapContainer center={[46.449, 2.210]} zoom={6} style={{height: "600px"}}>
|
||||
<MapContainer ref={mapRef} center={[(dep.lat + arr.lat) / 2, (dep.lng + arr.lng) / 2]} zoom={6} style={{height: "600px"}}>
|
||||
<TileLayer
|
||||
attribution="© Les contributeur⋅rices d'<a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a>"
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
/>
|
||||
<Marker position={dep} icon={redIcon} />
|
||||
<Marker position={arr} icon={greenIcon} />
|
||||
<Polyline positions={[dep, arr]} />
|
||||
<Marker position={depCoords} icon={redIcon} />
|
||||
<Marker position={arrCoords} icon={greenIcon} />
|
||||
<Polyline positions={[depCoords, arrCoords]} />
|
||||
</MapContainer>
|
||||
)
|
||||
}
|
||||
|
||||
function AirportSearch({name, updateFun}) {
|
||||
function AirportSearch({name, type, updateFun, dep, arr, updateFlights, mapRef}) {
|
||||
const [airports, setAirports] = useState([])
|
||||
|
||||
function autocomplete(event) {
|
||||
const target = event.target
|
||||
const value = target.value
|
||||
fetch(`/api/airports?search=${value}`).then(resp => resp.json()).then(setAirports)
|
||||
fetch(`/api/airports?search=${value}&limit=10`).then(resp => resp.json()).then(airports => {
|
||||
setAirports(airports)
|
||||
if (airports.length === 1)
|
||||
selectAirport(airports[0])
|
||||
})
|
||||
}
|
||||
|
||||
function selectAirport(airport) {
|
||||
updateFun(airport)
|
||||
if (type === 'dep')
|
||||
dep = airport
|
||||
else
|
||||
arr = airport
|
||||
|
||||
if (dep.icao_code && arr.icao_code)
|
||||
fetch(`/api/flights/${dep.icao_code}/${arr.icao_code}`).then(resp => resp.json()).then(updateFlights)
|
||||
mapRef.current.flyToBounds([[dep.lat, dep.lng], [arr.lat, arr.lng]])
|
||||
}
|
||||
|
||||
return <>
|
||||
<datalist id={name + "-list"}>
|
||||
{airports.map(airport => <>
|
||||
<option value={airport.icao_code}
|
||||
<option key={airport.icao_code}
|
||||
value={airport.icao_code}
|
||||
data-lat={airport.lat}
|
||||
data-lng={airport.lng}
|
||||
onClick={updateFun([airport.lat, airport.lng])}>{airport.name}</option>
|
||||
data-lng={airport.lng}>{airport.name}</option>
|
||||
</>)}
|
||||
</datalist>
|
||||
<input type="hidden" name={name + "-icao"}/>
|
||||
<input name={name} list={name + "-list"} onChange={autocomplete}/>
|
||||
<input name={name} list={name + "-list"} onInput={autocomplete}/>
|
||||
</>
|
||||
}
|
||||
|
||||
function FlightsTable({dep, arr, flights}) {
|
||||
return <div id={"flights-table"} style={{width: "100%"}}>
|
||||
<h1>{dep.name} --> {arr.name} ({distance(dep, arr)} km)</h1>
|
||||
<ul>
|
||||
{flights.map(flight => <li>
|
||||
{flight.days.join(', ')}, {flight.dep_time_utc} => {flight.arr_time_utc} ({flight.duration} minutes)
|
||||
</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [dep, setDep] = useState([0, 0])
|
||||
const [arr, setArr] = useState([0, 0])
|
||||
const [dep, setDep] = useState({lat: 0, lng: 0})
|
||||
const [arr, setArr] = useState({lat: 0, lng: 0})
|
||||
const [flights, setFlights] = useState([])
|
||||
const mapRef = useRef(null)
|
||||
|
||||
return <>
|
||||
<Map dep={dep} arr={arr}></Map>
|
||||
<AirportSearch name={"departure"} updateFun={setDep}></AirportSearch>
|
||||
<AirportSearch name={"arrival"} updateFun={setArr}></AirportSearch>
|
||||
<Map mapRef={mapRef} dep={dep} arr={arr} />
|
||||
<AirportSearch name={"departure"} type={"dep"} updateFun={setDep} dep={dep} arr={arr} updateFlights={setFlights} mapRef={mapRef} />
|
||||
<AirportSearch name={"arrival"} type={"arr"} updateFun={setArr} dep={dep} arr={arr} updateFlights={setFlights} mapRef={mapRef} />
|
||||
<FlightsTable dep={dep} arr={arr} flights={flights} />
|
||||
</>
|
||||
}
|
||||
|
||||
|
@ -20,15 +20,30 @@ app.get("/api", (req, res) => {
|
||||
|
||||
app.get("/api/airports", (req, res) => {
|
||||
const search = req.query.search.toLowerCase()
|
||||
let where = {}
|
||||
let options = {}
|
||||
|
||||
if (search) {
|
||||
let or_array = []
|
||||
for (let col_name of ['name', 'icao_code', 'iata_code'])
|
||||
or_array.push(db.sequelize.where(db.sequelize.fn('lower', db.sequelize.col(col_name)),
|
||||
{[db.Sequelize.Op.like]: `%${search}%`}))
|
||||
where = {[db.Sequelize.Op.or]: or_array}
|
||||
options.where = {[db.Sequelize.Op.or]: or_array}
|
||||
}
|
||||
Airport.findAll({where: where}).then(airports => res.json(airports))
|
||||
|
||||
options.limit = 10
|
||||
if (req.query.limit) {
|
||||
const limit = parseInt(req.query.limit)
|
||||
if (limit >= 1)
|
||||
options.limit = limit
|
||||
}
|
||||
|
||||
if (req.query.page) {
|
||||
const page = parseInt(req.query.page)
|
||||
if (page > 1)
|
||||
options.offset = (page - 1) * options.limit
|
||||
}
|
||||
|
||||
Airport.findAll(options).then(airports => res.json(airports))
|
||||
})
|
||||
|
||||
app.get("/api/airport/:icao_code", (req, res) => {
|
||||
@ -43,7 +58,7 @@ app.get("/api/airport/:icao_code", (req, res) => {
|
||||
|
||||
app.get("/api/flights/:dep_icao", (req, res) => {
|
||||
const dep_icao = req.params.dep_icao
|
||||
Flight.findAll({where: {dep_icao: dep_icao}}).then(data => {
|
||||
Flight.findAll({order: [['dep_time_utc']], where: {dep_icao: dep_icao}}).then(data => {
|
||||
if (data)
|
||||
res.json(data)
|
||||
else
|
||||
@ -54,7 +69,7 @@ app.get("/api/flights/:dep_icao", (req, res) => {
|
||||
app.get("/api/flights/:dep_icao/:arr_icao", (req, res) => {
|
||||
const dep_icao = req.params.dep_icao
|
||||
const arr_icao = req.params.arr_icao
|
||||
Flight.findAll({where: {dep_icao: dep_icao, arr_icao: arr_icao}}).then(data => {
|
||||
Flight.findAll({order: [['dep_time_utc']], where: {dep_icao: dep_icao, arr_icao: arr_icao}}).then(data => {
|
||||
if (data)
|
||||
res.json(data)
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user