@flybywiresim/map
Advanced tools
Comparing version 0.2.0 to 0.3.0
import { Airport } from "@flybywiresim/api-client"; | ||
import React, { useEffect, useState } from "react"; | ||
import ArrivalWhite from './icons/arrival_white.png'; | ||
import DepartureWhite from './icons/departure_white.png'; | ||
import ArrivalWhite from './res/icons/arrival_white.png'; | ||
import DepartureWhite from './res/icons/departure_white.png'; | ||
import { FeatureGroup, Marker, Tooltip } from "react-leaflet"; | ||
@@ -39,6 +39,8 @@ import L from "leaflet"; | ||
for (const search of searches) { | ||
try { | ||
airports.push(await getAirport(search.icao, search.airportType)); | ||
} catch (e) { | ||
console.error(e); | ||
if (!!search.icao) { | ||
try { | ||
airports.push(await getAirport(search.icao, search.airportType)); | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
} | ||
@@ -60,11 +62,11 @@ } | ||
key: arptToShow.airport.icao + '-' + arptToShow.airportType, | ||
zIndexOffset: 9999, | ||
position: [arptToShow.airport.lat, arptToShow.airport.lon], | ||
icon: L.divIcon({ | ||
iconSize: [20, 17], | ||
iconAnchor: [10, 8.5], | ||
className: "mapIcon", | ||
html: `<img alt="${arptToShow.airport.name}" | ||
src="${arptToShow.airportType === AirportType.Arrival ? props.arrivalIcon || ArrivalWhite : props.departureIcon || DepartureWhite}" />` | ||
icon: L.icon({ | ||
iconSize: [26, 26], | ||
iconAnchor: [13, 13], | ||
iconUrl: arptToShow.airportType === AirportType.Arrival ? props.arrivalIcon || ArrivalWhite : props.departureIcon || DepartureWhite | ||
}) | ||
}, /*#__PURE__*/React.createElement(Tooltip, { | ||
className: "airport-tooltip", | ||
direction: "top", | ||
@@ -71,0 +73,0 @@ permanent: true |
@@ -5,2 +5,3 @@ import { Marker, Popup } from "react-leaflet"; | ||
import { Telex } from "@flybywiresim/api-client"; | ||
import useInterval from "./hooks/useInterval"; | ||
@@ -33,9 +34,14 @@ const FlightMarker = props => { | ||
} | ||
if (props.autoUpdate) { | ||
useInterval(async () => { | ||
if (props.autoUpdate && props.connection !== undefined) { | ||
await findAndSetConnection(props.connection); | ||
} | ||
}, 15000, { | ||
runOnStart: true, | ||
additionalDeps: [props.autoUpdate] | ||
}); | ||
} | ||
}, [props.connection]); | ||
useEffect(() => { | ||
if (props.autoUpdate && props.connection !== undefined) { | ||
const interval = setInterval(() => findAndSetConnection(props.connection), 15000); | ||
return () => clearInterval(interval); | ||
} | ||
}, [props.autoUpdate]); | ||
@@ -49,3 +55,10 @@ async function findAndSetConnection(connection) { | ||
if (typeof connection === "string") { | ||
setConnection(await Telex.findConnection(connection)); | ||
const conns = await Telex.findConnections(connection); | ||
if (conns.length !== 1 && conns[0].flight !== connection) { | ||
console.error('Current FLT NBR did not return 1 result'); | ||
return; | ||
} | ||
setConnection(conns[0]); | ||
} else { | ||
@@ -63,9 +76,14 @@ setConnection(await Telex.fetchConnection(connection.id)); | ||
icon: L.divIcon({ | ||
iconSize: [20, 23], | ||
iconAnchor: [10, 6.5], | ||
className: 'mapIcon', | ||
html: `<img alt="${connection.flight}" src="${props.isHighlighted && !!props.highlightIcon ? props.highlightIcon : props.icon}" | ||
style="transform-origin: center; transform: rotate(${connection.heading}deg);"/>` | ||
iconSize: [25, 27], | ||
iconAnchor: [12.5, 13.5], | ||
className: 'aircraft-marker', | ||
html: `<img alt="${connection.flight}" | ||
src="${props.isHighlighted && !!props.highlightIcon ? props.highlightIcon : props.icon}" | ||
style="transform-origin: center; transform: rotate(${connection.heading}deg);" | ||
width="25" height="27" | ||
/>` | ||
}) | ||
}, /*#__PURE__*/React.createElement(Popup, { | ||
closeButton: false, | ||
className: "aircraft-popup", | ||
onOpen: () => props.onPopupOpen ? props.onPopupOpen() : {}, | ||
@@ -72,0 +90,0 @@ onClose: () => props.onPopupClose ? props.onPopupClose() : {} |
@@ -1,2 +0,2 @@ | ||
import React, { useEffect, useState } from "react"; | ||
import React, { useState } from "react"; | ||
import { FeatureGroup, useMapEvents } from "react-leaflet"; | ||
@@ -6,2 +6,3 @@ import { Telex } from "@flybywiresim/api-client"; | ||
import FlightMarker from "./FlightMarker"; | ||
import useInterval from "./hooks/useInterval"; | ||
@@ -22,11 +23,8 @@ const FlightsLayer = props => { | ||
const [selectedConnection, setSelectedConnection] = useState(null); | ||
useEffect(() => { | ||
if (props.refreshInterval && props.refreshInterval > 0) { | ||
const interval = setInterval(() => getLocationData(false, map.getBounds()), props.refreshInterval); | ||
return () => clearInterval(interval); | ||
} | ||
}, [props.refreshInterval]); | ||
useEffect(() => { | ||
getLocationData(false, bounds); | ||
}, [bounds]); | ||
useInterval(async () => { | ||
await getLocationData(false, map.getBounds()); | ||
}, props.refreshInterval || 10000, { | ||
runOnStart: true, | ||
additionalDeps: [props.hideOthers, bounds] | ||
}); | ||
@@ -53,7 +51,21 @@ async function getLocationData(staged = false, bounds) { | ||
if (props.hideOthers) { | ||
const flt = await Telex.findConnection(props.currentFlight); | ||
flights.push(flt); | ||
} else { | ||
flights = await Telex.fetchAllConnections(apiBounds, staged ? setData : undefined); | ||
try { | ||
if (props.hideOthers) { | ||
const flt = await Telex.findConnections(props.currentFlight); | ||
if (flt.length !== 1 && flt[0].flight !== props.currentFlight) { | ||
console.error("Current FLT NBR returns more than 1 result"); | ||
return; | ||
} | ||
flights.push(flt[0]); | ||
map.flyTo({ | ||
lat: flt[0].location.y, | ||
lng: flt[0].location.x | ||
}); | ||
} else { | ||
flights = await Telex.fetchAllConnections(apiBounds, staged ? setData : undefined); | ||
} | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
@@ -63,3 +75,6 @@ | ||
setData(flights); | ||
props.updateFlightData(flights); | ||
if (props.onConnectionsUpdate) { | ||
props.onConnectionsUpdate(flights); | ||
} | ||
} | ||
@@ -72,3 +87,3 @@ | ||
highlightIcon: props.planeIconHighlight, | ||
isHighlighted: props.searchedFlight === connection.flight || props.currentFlight === connection.flight, | ||
isHighlighted: props.searchedFlight && props.searchedFlight.flight === connection.flight || props.currentFlight === connection.flight, | ||
onPopupOpen: () => setSelectedConnection(connection), | ||
@@ -75,0 +90,0 @@ onPopupClose: () => setSelectedConnection(null) |
143
dist/Map.js
@@ -1,14 +0,20 @@ | ||
import React, { useState, useEffect } from "react"; | ||
import { TileLayer, MapContainer } from "react-leaflet"; | ||
import React, { useState } from "react"; | ||
import { TileLayer, MapContainer, ZoomControl } from "react-leaflet"; | ||
import { NmScale } from '@marfle/react-leaflet-nmscale'; | ||
import WeatherLayer from "./WeatherLayer"; | ||
import FlightsLayer from './FlightsLayer'; | ||
import SearchBar from './Search'; | ||
import InfoPanel from './InfoPanel'; | ||
import MenuPanel from './MenuPanel'; | ||
import "leaflet/dist/leaflet.css"; | ||
import "./Map.scss"; | ||
import ArrivalWhite from './icons/arrival_white.png'; | ||
import ArrivalGray from './icons/arrival_gray.png'; | ||
import DepartureWhite from './icons/departure_white.png'; | ||
import DepartureGray from './icons/arrival_gray.png'; | ||
import PlaneCyan from './icons/plane_cyan.png'; | ||
import PlaneBlue from './icons/plane_blue.png'; | ||
import ArrivalWhite from './res/icons/arrival_white.png'; | ||
import ArrivalGray from './res/icons/arrival_gray.png'; | ||
import DepartureWhite from './res/icons/departure_white.png'; | ||
import DepartureGray from './res/icons/departure_gray.png'; | ||
import PlaneCyan from './res/icons/plane_cyan.png'; | ||
import PlaneBlue from './res/icons/plane_blue.png'; | ||
import CartoDarkPreview from './res/previews/carto-dark.png'; | ||
import CartoLightPreview from './res/previews/carto-light.png'; | ||
import OsmPreview from './res/previews/osm.png'; | ||
import { MeasureControl } from "./MeasureControl"; | ||
import useLocalStorage from "./hooks/useLocalStorage"; | ||
@@ -25,3 +31,4 @@ const Map = props => { | ||
departureIcon: DepartureWhite, | ||
arrivalIcon: ArrivalWhite | ||
arrivalIcon: ArrivalWhite, | ||
previewImageUrl: CartoDarkPreview | ||
}, { | ||
@@ -36,3 +43,4 @@ id: 2, | ||
departureIcon: DepartureGray, | ||
arrivalIcon: ArrivalGray | ||
arrivalIcon: ArrivalGray, | ||
previewImageUrl: CartoLightPreview | ||
}, { | ||
@@ -47,64 +55,27 @@ id: 3, | ||
departureIcon: DepartureGray, | ||
arrivalIcon: ArrivalGray | ||
arrivalIcon: ArrivalGray, | ||
previewImageUrl: OsmPreview | ||
}]; | ||
const [currentFlight, setCurrentFlight] = useState(props.currentFlight || ""); | ||
const [selectedTile, setSelectedTile] = useState(setAndFind(props.forceTileset || "")); | ||
const [flightData, setFlightData] = useState([]); | ||
const [searchedFlight, setSearchedFlight] = useState(""); | ||
const [keyMap, setKeyMap] = useState(Math.random()); | ||
useEffect(() => { | ||
setKeyMap(Math.random()); | ||
}, [selectedTile]); | ||
function setAndFind(key) { | ||
if (key) { | ||
window.localStorage.setItem("PreferredTileset", key); | ||
} | ||
return findPreferredTile(); | ||
} | ||
function findPreferredTile() { | ||
try { | ||
const storedTiles = window.localStorage.getItem("PreferredTileset"); | ||
if (!storedTiles) { | ||
return availableTileSets[0]; | ||
} | ||
return availableTileSets.find(x => x.value === storedTiles) || availableTileSets[0]; | ||
} catch { | ||
return availableTileSets[0]; | ||
} | ||
} | ||
function updateFlightData(data) { | ||
setFlightData(data); | ||
} | ||
function updateSearchedFlight(flightName) { | ||
setSearchedFlight(flightName); | ||
} | ||
function selectTile(tile) { | ||
if (!tile) { | ||
return availableTileSets[0]; | ||
} | ||
const newTiles = availableTileSets.find(x => x.value === tile) || availableTileSets[0]; | ||
setSelectedTile(newTiles); | ||
window.localStorage.setItem("PreferredTileset", newTiles.value); | ||
} | ||
const [selectedTile, setSelectedTile] = useLocalStorage("tileSet", availableTileSets[0], { | ||
valueOverride: !!props.forceTileset && availableTileSets.find(x => x.value === props.forceTileset) | ||
}); | ||
const [searchedFlight, setSearchedFlight] = useState(); | ||
const [weatherOpacity, setWeatherOpacity] = useState(props.weatherOpacity || 0.2); | ||
const [showOthers, setShowOthers] = useState(!props.hideOthers); | ||
return /*#__PURE__*/React.createElement(MapContainer, { | ||
id: "mapid", | ||
key: keyMap, | ||
id: "live-map", | ||
center: props.center || [50, 8], | ||
zoom: props.zoom || 5, | ||
scrollWheelZoom: !props.disableScroll, | ||
worldCopyJump: true | ||
worldCopyJump: true, | ||
zoomControl: false | ||
}, /*#__PURE__*/React.createElement(TileLayer, { | ||
zIndex: 0, | ||
attribution: selectedTile.attribution, | ||
url: selectedTile.url | ||
}), !props.disableFlights ? /*#__PURE__*/React.createElement(FlightsLayer, { | ||
url: selectedTile.url, | ||
key: selectedTile.value | ||
}), !props.disableWeather ? /*#__PURE__*/React.createElement(WeatherLayer, { | ||
opacity: weatherOpacity | ||
}) : /*#__PURE__*/React.createElement(React.Fragment, null), !props.disableFlights ? /*#__PURE__*/React.createElement(FlightsLayer, { | ||
planeIcon: selectedTile.planeIcon, | ||
@@ -114,17 +85,39 @@ planeIconHighlight: selectedTile.planeIconHighlight, | ||
arrivalIcon: selectedTile.arrivalIcon, | ||
updateFlightData: updateFlightData, | ||
currentFlight: currentFlight, | ||
searchedFlight: searchedFlight, | ||
refreshInterval: props.refreshInterval || 10000, | ||
hideOthers: props.hideOthers | ||
}) : /*#__PURE__*/React.createElement(React.Fragment, null), !props.disableInfo ? /*#__PURE__*/React.createElement(InfoPanel, { | ||
hideOthers: !showOthers | ||
}) : /*#__PURE__*/React.createElement(React.Fragment, null), !props.disableMenu ? /*#__PURE__*/React.createElement(MenuPanel, { | ||
onFound: conn => setSearchedFlight(conn), | ||
onNotFound: () => setSearchedFlight(undefined), | ||
onReset: () => setSearchedFlight(undefined), | ||
weatherOpacity: weatherOpacity, | ||
onWeatherOpacityChange: setWeatherOpacity, | ||
activeTileSet: selectedTile, | ||
availableTileSets: availableTileSets, | ||
onTileSetChange: setSelectedTile, | ||
refreshInterval: props.refreshInterval || 10000, | ||
tiles: availableTileSets, | ||
changeTiles: selectTile | ||
}) : /*#__PURE__*/React.createElement(React.Fragment, null), !props.disableSearch ? /*#__PURE__*/React.createElement(SearchBar, { | ||
flightData: flightData, | ||
updateSearchedFlight: updateSearchedFlight | ||
}) : /*#__PURE__*/React.createElement(React.Fragment, null)); | ||
currentFlight: currentFlight, | ||
onCurrentFlightChange: setCurrentFlight, | ||
showOthers: showOthers, | ||
onShowOthersChange: setShowOthers | ||
}) : /*#__PURE__*/React.createElement(React.Fragment, null), /*#__PURE__*/React.createElement(ZoomControl, { | ||
position: props.zoomPosition || "bottomright" | ||
}), /*#__PURE__*/React.createElement(NmScale, null), /*#__PURE__*/React.createElement(MeasureControl, { | ||
position: props.zoomPosition || "bottomright", | ||
unit: "nauticalmiles", | ||
showBearings: true, | ||
showUnitControl: true, | ||
showClearControl: true, | ||
tempLine: { | ||
color: '#00C2CB', | ||
weight: 2 | ||
}, | ||
fixedLine: { | ||
color: '#00C2CB', | ||
weight: 2 | ||
} | ||
})); | ||
}; | ||
export default Map; |
{ | ||
"name": "@flybywiresim/map", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "FlyByWire Simulations live map", | ||
@@ -16,6 +16,9 @@ "private": false, | ||
], | ||
"license": "MIT", | ||
"main": "dist/Map.js", | ||
"dependencies": { | ||
"@flybywiresim/api-client": "^0.5.0", | ||
"@flybywiresim/api-client": "^0.6.0", | ||
"@marfle/react-leaflet-nmscale": "^2.0.0", | ||
"leaflet": "^1.7.1", | ||
"leaflet.polylinemeasure": "git+https://github.com/ppete2/Leaflet.PolylineMeasure.git", | ||
"react": "^17.0.1", | ||
@@ -22,0 +25,0 @@ "react-dom": "^17.0.1", |
Sorry, the diff of this file is not supported yet
Git dependency
Supply chain riskContains a dependency which resolves to a remote git URL. Dependencies fetched from git URLs are not immutable and can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
1366201
22
0
670
7
1
2
+ Addedleaflet.polylinemeasure@git+https://github.com/ppete2/Leaflet.PolylineMeasure.git
+ Added@flybywiresim/api-client@0.6.0(transitive)
+ Added@marfle/react-leaflet-nmscale@2.0.1(transitive)
- Removed@flybywiresim/api-client@0.5.0(transitive)