ADD: added Debug perceived tracklist and minimap

This commit is contained in:
Henry Winkel
2024-03-07 18:36:57 +01:00
parent 5a59f87f13
commit b17c62ae09
13 changed files with 468 additions and 60 deletions

View File

@@ -12,6 +12,7 @@
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.2", "bootstrap": "^5.3.2",
"leaflet": "^1.9.4",
"leaflet-contextmenu": "^1.4.0", "leaflet-contextmenu": "^1.4.0",
"milsymbol": "^2.2.0", "milsymbol": "^2.2.0",
"react": "^18.2.0", "react": "^18.2.0",
@@ -11822,8 +11823,7 @@
"node_modules/leaflet": { "node_modules/leaflet": {
"version": "1.9.4", "version": "1.9.4",
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA=="
"peer": true
}, },
"node_modules/leaflet-contextmenu": { "node_modules/leaflet-contextmenu": {
"version": "1.4.0", "version": "1.4.0",

View File

@@ -7,6 +7,7 @@
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.2", "bootstrap": "^5.3.2",
"leaflet": "^1.9.4",
"leaflet-contextmenu": "^1.4.0", "leaflet-contextmenu": "^1.4.0",
"milsymbol": "^2.2.0", "milsymbol": "^2.2.0",
"react": "^18.2.0", "react": "^18.2.0",

View File

@@ -1,6 +1,5 @@
import React from "react"; import React from "react";
import {w3cwebsocket as W3CWebSocket} from "websocket" import {w3cwebsocket as W3CWebSocket} from "websocket"
import MyMap from "./components/map/map.jsx"
import PerceivedTruth from "./components/perceivedTruth/perceivedTruth.jsx"; import PerceivedTruth from "./components/perceivedTruth/perceivedTruth.jsx";
import "./Debug.scss" import "./Debug.scss"
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
@@ -20,6 +19,8 @@ const config = {
function Scenarios() function Scenarios()
{ {
const [trackList, settrackList] = useState([]); const [trackList, settrackList] = useState([]);
const [entityTracklist, setEntityTracklist] = useState([]);
const [clientConnected, setclientConnected] = useState(false); const [clientConnected, setclientConnected] = useState(false);
// const [client, setclient] = useState(W3CWebSocket); // const [client, setclient] = useState(W3CWebSocket);
@@ -55,14 +56,16 @@ useEffect(() => {
if(message.data !== "null") if(message.data !== "null")
{ {
// console.log(message.data);
const dataFromServer = JSON.parse(message.data); const dataFromServer = JSON.parse(message.data);
// console.log(dataFromServer);
if(dataFromServer.Data === "COP") if(dataFromServer.Data === "COP")
{ {
settrackList(dataFromServer.Entities); settrackList(dataFromServer.Entities);
}else }else
{ {
console.log(message.data); // console.log(dataFromServer);
setEntityTracklist(dataFromServer)
} }
} }
@@ -115,10 +118,10 @@ return(
<div className="InfoPane" > <div className="InfoPane" >
<p>Debug</p> <p>Debug</p>
<PerceivedTruth Client={client} Tracklist= {trackList} /> <PerceivedTruth Client={client} EntityTracklist={entityTracklist} Tracklist= {trackList} />
</div> </div>
<MyMap />
</div> </div>

View File

@@ -4,6 +4,6 @@
} }
.InfoPane{ .InfoPane{
width: 70%; width: 100%;
padding-left: 1rem padding-left: 1rem
} }

View File

@@ -1,26 +0,0 @@
import { useLeafletContext } from '@react-leaflet/core'
import { MapContainer, TileLayer} from 'react-leaflet'
import L from 'leaflet'
import { useEffect, useRef } from 'react'
import "./map.scss"
const center = [54, 8];
function MyMap() {
return (
<div className='Smallapmap' >
<MapContainer center={center} zoom={6} attributionControl={false}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
</div>
)
}
export default MyMap;

View File

@@ -0,0 +1,185 @@
import { useLeafletContext } from '@react-leaflet/core'
import { MapContainer, TileLayer, Marker,Tooltip} from 'react-leaflet'
import L, { Icon, icon } from 'leaflet'
import { useEffect, useState,useRef, useCallback,useMemo } from 'react'
import "./map.scss"
import { OwnShipIcon, createIcon } from '../../../../SimControl/components/OpenSeaMap/icon'
const zoom = 9
function DisplayPosition({ map,center }) {
const [position, setPosition] = useState(() => map.getCenter())
// const onClick = useCallback(() => {
// map.setView(center, zoom)
// }, [map])
const onMove = useCallback(() => {
setPosition(map.getCenter())
}, [map])
useEffect(() => {
map.setView(center, zoom)
}, [center, map])
useEffect(() => {
map.on('move', onMove)
return () => {
map.off('move', onMove)
}
}, [map, onMove])
return (
<p>
latitude: {position.lat.toFixed(4)}, longitude: {position.lng.toFixed(4)}{' '}
{/* <button onClick={onClick}>reset</button> */}
</p>
)
}
function MyMap({center,Tracklist}) {
const [map, setMap] = useState(null)
const [mapcenter, setMapcenter] = useState([51.505, -0.09])
const [isFocused, setIsFocused] = useState(false)
const [trackList,setTracklist] = useState([])
// const OwnShipIcon = L.icon({
// iconUrl: 'Own_Ship.svg',
// iconSize: [50, 50], // size of the icon
// });
useEffect(() => {
// console.log(center);
if(center.length !== 0)
{
setMapcenter(center);
setIsFocused(true);
}
}, [center]);
useEffect(() => {
// console.log(Tracklist);
// makeList(Tracklist.Tracks)
var tracks = Tracklist.Tracks
var list = [];
// var Symbol = {
// ID: "1234",
// Name:"Own Ship",
// Position: mapcenter ,
// IconData: OwnShipIcon,
// }
// list.push(Symbol);
// setTracklist(list);
if(tracks === undefined)
{
return;
}
tracks.forEach(element => {
console.log(element)
var Symbol = {
ID: element.ID,
Name:element.Name,
Position: [element.Position.PositionGeodesic.lat, element.Position.PositionGeodesic.lon] ,
IconData: createIcon(element.Type, element.Side),
}
list.push(Symbol);
});
// console.log(list);
setTracklist(list);
}, [Tracklist, mapcenter]);
// function makeList(tracks)
// {
// }
function makeIcons()
{
if(trackList === undefined)
{
return;
}
var list =[];
trackList.forEach(element => {
list.push(
<Marker name={element.Name} key={element.ID} icon={element.IconData} position={element.Position} >
<Tooltip direction='bottom' offset={[0,10]} opacity={1} permanent>
<span>{element.Name}</span>
</Tooltip>
</Marker>)
})
return(
list
)
}
const displayMap = useMemo(
() => (
<MapContainer
center={mapcenter}
zoom={zoom}
attributionControl={false}
// scrollWheelZoom={false}
ref={setMap}>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{isFocused ? <Marker icon={OwnShipIcon} position={mapcenter} >
<Tooltip direction='bottom' offset={[0,13]} opacity={1} permanent>
<span>{"Own Ship"}</span>
</Tooltip>
</Marker> :null }
{ makeIcons()}
{
}
</MapContainer>
),
[isFocused, mapcenter, trackList],
)
return (
<div className='Smallapmap'>
{map ? <DisplayPosition map={map} center={mapcenter} /> : null}
{displayMap }
</div>
)
}
export default MyMap;

View File

@@ -2,7 +2,7 @@
// display: flex; // display: flex;
// padding-top: 10px; // padding-top: 10px;
height: 500px; height: 500px;
width: 500px; width: 100%;
// padding-left: 20%; // padding-left: 20%;
display: inline-flex; display: inline-flex;
// height: 80%; // height: 80%;

View File

@@ -0,0 +1,66 @@
.App {
display: flex;
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.leaflet-container {
width: 70vw;
height: 100vh;
}
.sidebar {
box-sizing: border-box;
padding: 2em;
width: 30vw;
}
.sidebar h2,
.sidebar p,
.sidebar ul {
text-align: left;
}
.sidebar h2 {
margin-top: 0;
}
.sidebar button {
width: 100%;
font-weight: bold;
padding: .8em 1em;
}

View File

@@ -1,13 +1,22 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { getWSTestMessage ,getTracklist } from '../../../api/APICalls'; import { getWSTestMessage ,getTracklist } from '../../../api/APICalls';
import MyMap from "./map/map.jsx"
import "./perceivedTruth.scss"
import TrackList from './tracklist/tracklist.jsx';
function PerceivedTruth(props) function PerceivedTruth(props)
{ {
const [selectedOption, setSelectedOption] = useState('option1') const [selectedOption, setSelectedOption] = useState('option1')
const [selectedOptionFull, setSelectedOptionFull] = useState({
ID : null,
Label:"",
Position: []
})
const [selectOptions, setSelectOptions] = useState([]) const [selectOptions, setSelectOptions] = useState([])
const [trackList, settrackList] = useState([]); const [trackList, settrackList] = useState([]);
@@ -16,6 +25,14 @@ function PerceivedTruth(props)
const handleSubmit = (event) => { const handleSubmit = (event) => {
if(selectedOption !== "option1" && selectedOption !== "" ) if(selectedOption !== "option1" && selectedOption !== "" )
{ {
let updatedValue = getAttributesForID(selectedOption);
setSelectedOptionFull(selectedOptionFull => ({
...selectedOptionFull,
...updatedValue
}));
client.send(getTracklist(selectedOption)); client.send(getTracklist(selectedOption));
event.preventDefault() event.preventDefault()
console.log(`Submitted selected option: ${selectedOption}`) console.log(`Submitted selected option: ${selectedOption}`)
@@ -23,6 +40,28 @@ function PerceivedTruth(props)
} }
} }
function getAttributesForID(ID)
{
let attributes = {
ID: undefined,
Name: "",
Position : []
};
selectOptions.forEach(element => {
// console.log(element);
if(element.value === ID)
{
attributes.ID = ID;
attributes.Name = element.label;
attributes.Position = element.position;
}
})
return attributes;
}
function prepareTracklistForSelect(Tracklist) function prepareTracklistForSelect(Tracklist)
{ {
if(Tracklist!== undefined) if(Tracklist!== undefined)
@@ -33,7 +72,8 @@ function PerceivedTruth(props)
var item = var item =
{ {
value : element.id, value : element.id,
label : element.Name label : element.Name,
position: element.Position
}; };
@@ -49,36 +89,42 @@ function PerceivedTruth(props)
useEffect(() => { useEffect(() => {
//Runs on the first render //Runs on the first render
//And any time any dependency value changes //And any time any dependency value changes
// console.log(props); console.log(props.EntityTracklist);
setclient(props.Client); setclient(props.Client);
settrackList(props.Tracklist); settrackList(props.Tracklist);
prepareTracklistForSelect(trackList); prepareTracklistForSelect(trackList);
}, [props]);
}, [props, trackList]);
return( return(
<div> <div className='box'>
<form onSubmit={handleSubmit}> <div className='EntityTracklist'>
<form onSubmit={handleSubmit}>
<label htmlFor="my-select">Select Track:</label>
<select
id="my-select"
value={selectedOption}
onChange={(event) => setSelectedOption(event.target.value)}
>
<option> </option>
{selectOptions.map((option, index) => (
<option key={index} value={option.value} label={option.label} />
))}
</select>
<button type="submit">Submit</button>
</form>
<p>{ selectedOptionFull.Label}</p>
<label htmlFor="my-select">Select Track:</label> <TrackList Tracklist ={props.EntityTracklist} />
<select </div>
id="my-select" <div className='SideMap'>
value={selectedOption} <MyMap center={selectedOptionFull.Position} Tracklist ={props.EntityTracklist} />
onChange={(event) => setSelectedOption(event.target.value)} </div>
>
<option> </option>
{selectOptions.map((option, index) => (
<option key={index} value={option.value} label={option.label} />
))}
</select>
<button type="submit">Submit</button>
</form>
</div> </div>
)} )}

View File

@@ -0,0 +1,14 @@
.box{
display: flex;
width: 100%;
}
.EntityTracklist
{
width: 50%;
}
.SideMap{
width: 40%;
justify-content: center;
margin: 0 auto;
}

View File

@@ -0,0 +1,89 @@
import React, { useEffect, useState } from 'react'
import "./tracklist.scss"
import round from "../../../../Utils.jsx"
function TrackList(props)
{
const [tracklist, setTracklist] = useState(Array)
useEffect(() => {
setTracklist(Array);
// console.log(props)
}, []);
useEffect(() => {
if(props.Tracklist.Tracks !== undefined)
{
setTracklist(props.Tracklist.Tracks);
}
// console.log(props)
}, [props]);
function MakeSensorList(props)
{
if(props === undefined)
{
return;
}
var list = [];
props.Sensors.forEach(element => {
list.push(<span> {element.Name} Range: {element.Range} NM </span>)
});
return(list);
}
return (
<div>
<div class="divTable">
<div class="divTableBody">
<div class="divTableRow">
<div class="divTableCell">NR</div>
<div class="divTableCell">Name</div>
<div class="divTableCell">Position</div>
<div class="divTableCell">Bearing</div>
<div class="divTableCell">Range</div>
<div class="divTableCell">Sensors</div>
</div>
{/* {<MakeRow />} */}
{
tracklist.map( (elem,index) => {
if(elem.Position !== undefined)
{
// console.log(elem)
return(
<div class="divTableRow">
<div class="divTableCell">{index}</div>
<div class="divTableCell">{elem.Name}</div>
<div class="divTableCell">{round(elem.Position.PositionGeodesic.lat,4)}, {round(elem.Position.PositionGeodesic.lon,4)}</div>
<div class="divTableCell">{round(elem.Bearing,2)}</div>
<div class="divTableCell">{round(elem.Distance,2)}</div>
<div class="divTableCell">{MakeSensorList(elem) }</div>
</div>
)
}
})
}
</div>
</div>
</div>
)}
export default TrackList;

View File

@@ -0,0 +1,30 @@
/* DivTable.com */
.divTable{
display: table;
width: 100%;
}
.divTableRow {
display: table-row;
}
.divTableHeading {
background-color: #EEE;
display: table-header-group;
}
.divTableCell, .divTableHead {
border: 1px solid #999999;
display: table-cell;
padding: 3px 10px;
}
.divTableHeading {
background-color: #EEE;
display: table-header-group;
font-weight: bold;
}
.divTableFoot {
background-color: #EEE;
display: table-footer-group;
font-weight: bold;
}
.divTableBody {
display: table-row-group;
}

View File

@@ -14,7 +14,7 @@ import Track from "./Track.tsx";
import './SimControl.scss' import './SimControl.scss'
import EntityTrackList from "./components/EntityTrackList"; import EntityTrackList from "./components/EntityTrackList";
import { getWSTestMessage } from "../api/APICalls"; import { getCOP, getWSTestMessage } from "../api/APICalls";
@@ -126,7 +126,7 @@ class SimControl extends Component {
// Data: "COP" // Data: "COP"
// } // }
client.send(getWSTestMessage()); client.send(getCOP());
} }
getEntityFromID(Entities, SelectedEntity) getEntityFromID(Entities, SelectedEntity)