ADD: added react-router and updated structure of app
This commit is contained in:
220
webapp/src/components/SimControl/SimControl.jsx
Normal file
220
webapp/src/components/SimControl/SimControl.jsx
Normal file
@@ -0,0 +1,220 @@
|
||||
import React, { Component } from "react";
|
||||
import {w3cwebsocket as W3CWebSocket} from "websocket"
|
||||
// import Header from './components/Header';
|
||||
import Controls from "./components/control/controls";
|
||||
import OpenSeaMap from "./components/OpenSeaMap/OpenSeaMap";
|
||||
|
||||
const config = {
|
||||
// apiUrl: process.env.REACT_APP_WEBAPP_WS_URL,
|
||||
apiUrl: "192.168.3.13",
|
||||
apiProt: 30747
|
||||
}
|
||||
const client = new W3CWebSocket("ws://"+config.apiUrl+":"+config.apiProt+"/");
|
||||
|
||||
|
||||
|
||||
class SimControl extends Component {
|
||||
state = {
|
||||
Entities: [],
|
||||
EntityOnFocus: undefined,
|
||||
PositionClicked: undefined
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
console.log(config.apiUrl);
|
||||
|
||||
client.onopen = () => {
|
||||
console.log("Websocket Client for Map Connected");
|
||||
};
|
||||
|
||||
client.onmessage = (message) => {
|
||||
const dataFromServer = JSON.parse(message.data);
|
||||
// console.log('reply: ', dataFromServer);
|
||||
|
||||
if(dataFromServer.Data === "COP")
|
||||
{
|
||||
if(dataFromServer.Entities === undefined)
|
||||
{
|
||||
dataFromServer.Entities = [];
|
||||
}
|
||||
// console.log(this.state.EntityOnFocus);
|
||||
let tmp = new Array(); ;
|
||||
|
||||
if(this.state.Entities !== undefined && this.state.Entities.length !== 0){
|
||||
|
||||
if(dataFromServer.Entities.length > 0)
|
||||
{
|
||||
dataFromServer.Entities.forEach((elementFromWS, indexWS) => {
|
||||
|
||||
if (this.isStored(elementFromWS.id) !== true)
|
||||
{
|
||||
tmp.push(elementFromWS);
|
||||
}
|
||||
this.state.Entities.forEach((elementStored, indexStore) => {
|
||||
if(elementFromWS.id === elementStored.id)
|
||||
{
|
||||
// console.log(elementStored);
|
||||
|
||||
if(elementStored.onFocus !==true | elementStored.onFocus === undefined)
|
||||
{
|
||||
tmp.push(elementFromWS);
|
||||
|
||||
}else
|
||||
{
|
||||
tmp.push(elementStored);
|
||||
}
|
||||
}else{
|
||||
// console.log(elementFromWS);
|
||||
// tmp.push(elementFromWS);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}else{
|
||||
tmp = dataFromServer.Entities;
|
||||
}
|
||||
// console.log(tmp);
|
||||
this.setState((state) => ({
|
||||
// Entities: structuredClone(dataFromServer.Entities)
|
||||
Entities: structuredClone(tmp)
|
||||
|
||||
})
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// interval for updates
|
||||
setInterval(() => {
|
||||
this.updateEntities();
|
||||
}, 2000);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
isStored(id) {
|
||||
var found = false;
|
||||
this.state.Entities.forEach((elementStored, indexStore) => {
|
||||
if (id === elementStored.id)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
|
||||
}
|
||||
|
||||
|
||||
updateEntities()
|
||||
{
|
||||
var msg =
|
||||
{
|
||||
Type: "Request",
|
||||
Data: "COP"
|
||||
|
||||
}
|
||||
client.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
getEntityFromID(Entities, SelectedEntity)
|
||||
{
|
||||
// console.log(Entities);
|
||||
}
|
||||
|
||||
setEntityOnFocus(Entity)
|
||||
{
|
||||
if(Entity === undefined)
|
||||
{
|
||||
this.resetEntityOnFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
this.getEntityFromID(this.state.Entities,Entity)
|
||||
console.log(Entity);
|
||||
this.setState({
|
||||
EntityOnFocus: Entity
|
||||
});
|
||||
this.state.Entities.forEach((element, index) => {
|
||||
// console.log(element);
|
||||
|
||||
if(element.id === Entity.EntityID)
|
||||
{
|
||||
var tmpList = structuredClone(this.state.Entities);
|
||||
tmpList[index].onFocus = true;
|
||||
if(Entity.NewPos !== undefined)
|
||||
{
|
||||
tmpList[index].Position = Entity.NewPos
|
||||
}
|
||||
this.setState({
|
||||
Entities: structuredClone(tmpList)
|
||||
});
|
||||
if(Entity.dragged !== undefined)
|
||||
{
|
||||
if(Entity.dragged === true)
|
||||
{
|
||||
tmpList[index].dragged = true;
|
||||
}
|
||||
}
|
||||
console.log(tmpList[index]);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
resetEntityOnFocus()
|
||||
{
|
||||
if(this.state.EntityOnFocus !== undefined)
|
||||
{
|
||||
this.state.Entities.map((element ,index) => {
|
||||
if(element.id === this.state.EntityOnFocus.EntityID)
|
||||
{
|
||||
this.state.Entities[index].onFocus = false;
|
||||
}
|
||||
})
|
||||
console.log(this.state.Entities)
|
||||
this.setState({
|
||||
EntityOnFocus: undefined
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setFocusPosition(props)
|
||||
{
|
||||
|
||||
// console.log(Entity);
|
||||
this.setState({
|
||||
PositionClicked: props
|
||||
});
|
||||
}
|
||||
|
||||
Functions = {
|
||||
updateEntities: this.updateEntities.bind(this),
|
||||
resetEntityOnFocus: this.resetEntityOnFocus.bind(this)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const {name} = this.state;
|
||||
return (
|
||||
<div className="App">
|
||||
|
||||
<div className="Content">
|
||||
|
||||
<Controls Functions= {this.Functions} Client= {client} Entities= {this.state.Entities} updateEntities = {this.updateEntities} EntityOnFocus = {this.state.EntityOnFocus} PositionClicked = {this.state.PositionClicked} />
|
||||
|
||||
<OpenSeaMap Entities= {this.state.Entities} Client= {client} updateEntities = {this.updateEntities} setEntityOnFocus = {this.setEntityOnFocus.bind(this)} setFocusPosition = {this.setFocusPosition.bind(this)}/>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SimControl;
|
||||
0
webapp/src/components/SimControl/SimControl.scss
Normal file
0
webapp/src/components/SimControl/SimControl.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
import OpenSeaMap from "./OpenSeaMap.jsx.js";
|
||||
|
||||
|
||||
export default OpenSeaMap;
|
||||
@@ -0,0 +1,242 @@
|
||||
|
||||
// import { useMapEvents } from 'react-leaflet/hooks'
|
||||
import React, { Component } from "react";
|
||||
import { MapContainer, TileLayer,Marker, Popup, Tooltip,useMapEvents,contextmenu } from 'react-leaflet'
|
||||
import { friend,Hostile, iconShip,createIcon } from "./icon";
|
||||
import "./OpenSeaMap.scss";
|
||||
import {w3cwebsocket as W3CWebSocket} from "websocket";
|
||||
// import ContainerDimensions from 'react-container-dimensions';
|
||||
import {} from "leaflet-contextmenu";
|
||||
|
||||
|
||||
class OpenSeaMap extends Component {
|
||||
|
||||
state = {
|
||||
EntityOnFocus: undefined,
|
||||
}
|
||||
updateDimensions() {
|
||||
const height = window.innerWidth >= 950 ? window.innerHeight : 400
|
||||
this.setState({ height: height })
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.updateDimensions()
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener("resize", this.updateDimensions.bind(this))
|
||||
console.log(this.state.EntityOnFocus);
|
||||
|
||||
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("resize", this.updateDimensions.bind(this))
|
||||
}
|
||||
|
||||
|
||||
handleClick(e)
|
||||
{
|
||||
// console.log(e.target)
|
||||
// this.setState({ currentPos: e.latlng });
|
||||
// console.log(e.latlng);
|
||||
|
||||
// console.log("hello world");
|
||||
}
|
||||
|
||||
markerOnClick(e) {
|
||||
console.log(e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
setOnFocus(e)
|
||||
{
|
||||
console.log(e.relatedTarget);
|
||||
e.relatedTarget.dragging.enable();
|
||||
e.relatedTarget.options.draggable = true;
|
||||
var Ent = {
|
||||
EntityID : e.relatedTarget.options.data,
|
||||
NewPos : undefined
|
||||
}
|
||||
this.setState((state) =>({
|
||||
EntityOnFocus: Ent
|
||||
}))
|
||||
this.props.setEntityOnFocus(Ent)
|
||||
// this.draggable = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
makeIcon(index, entity,props,state)
|
||||
{
|
||||
var isOnFocus = false;
|
||||
if(this.state.EntityOnFocus !== undefined){
|
||||
// console.log(entity.id+ " " , this.state.EntityOnFocus);
|
||||
// console.log(props+ " " , this.state.EntityOnFocus);
|
||||
|
||||
if(entity.id === this.state.EntityOnFocus.EntityID)
|
||||
{
|
||||
isOnFocus = true
|
||||
// if(this.state.EntityOnFocus.NewPos !== undefined)
|
||||
// {
|
||||
// entity.pos = this.state.EntityOnFocus.NewPos;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var icon;
|
||||
icon = createIcon(entity.Type,entity.Side)
|
||||
return (
|
||||
<Marker name={entity.Name} key={index} icon={icon} position={entity.Position} data={entity.id}
|
||||
draggable={isOnFocus? true : false}
|
||||
contextmenu={true}
|
||||
contextmenuWidth={140}
|
||||
|
||||
contextmenuItems={[{
|
||||
text:"Edit",
|
||||
index:0,
|
||||
callback: this.setOnFocus.bind(this),
|
||||
},{
|
||||
text:"Delete",
|
||||
index: 1,
|
||||
callback: function() {
|
||||
var msg =
|
||||
{
|
||||
Data: "Entity",
|
||||
Type: "Delete",
|
||||
ID: entity.id,
|
||||
}
|
||||
console.log(JSON.stringify(msg));
|
||||
state.EntityOnFocus = undefined;
|
||||
props.setEntityOnFocus(undefined)
|
||||
|
||||
props.Client.send(JSON.stringify(msg))
|
||||
},
|
||||
// separator: true,
|
||||
}, {
|
||||
text:"Test",
|
||||
callback: this.markerOnClick.bind(this),
|
||||
// separator: true,
|
||||
index: 2
|
||||
}, {
|
||||
text:"Exit",
|
||||
callback: function()
|
||||
{
|
||||
state.EntityOnFocus = undefined;
|
||||
props.setEntityOnFocus(undefined);
|
||||
},
|
||||
// separator: true,
|
||||
index: 3
|
||||
}]}
|
||||
// contextmenuItems: [{
|
||||
// text: 'Circle 1',
|
||||
// callback: function() {
|
||||
// circleContextClick(circle1);
|
||||
// }
|
||||
// }]
|
||||
eventHandlers={{
|
||||
click: (e) => {
|
||||
// console.log(e.target);
|
||||
// var Ent = {
|
||||
// EntityID : e.target.options.data,
|
||||
// NewPos : undefined
|
||||
|
||||
// }
|
||||
// this.setState((state) =>({
|
||||
// EntityOnFocus: Ent
|
||||
// }))
|
||||
// this.props.setEntityOnFocus(Ent);
|
||||
|
||||
// this.props.setEntityOnFocus(e.target.options.data);
|
||||
},
|
||||
dragend: (e) =>
|
||||
{
|
||||
var Ent = {
|
||||
EntityID : e.target.options.data,
|
||||
NewPos : [e.target._latlng.lat,e.target._latlng.lng],
|
||||
dragged: true
|
||||
|
||||
}
|
||||
this.setState((state) =>({
|
||||
EntityOnFocus: Ent
|
||||
}))
|
||||
|
||||
this.props.setEntityOnFocus(Ent);
|
||||
// console.log(e.target);
|
||||
|
||||
// console.log(e.target._latlng);
|
||||
|
||||
},
|
||||
// contextmenu: (e) =>
|
||||
// {
|
||||
// console.log("right click");
|
||||
// }
|
||||
}}
|
||||
// eventHandlers={this.MarkerEventHandler}
|
||||
>
|
||||
|
||||
{/* <Popup>
|
||||
Omu-Aran the Head Post of Igbomina land,
|
||||
is a town in the Nigerian state of Kwara.
|
||||
It originated from Ife and currently the local
|
||||
government headquarters of Irepodun local government.
|
||||
</Popup> */}
|
||||
<Tooltip direction='bottom' offset={[0,13]} opacity={1} permanent>
|
||||
<span>{entity.Name}</span>
|
||||
</Tooltip>
|
||||
</Marker>
|
||||
);
|
||||
}
|
||||
|
||||
setPos(props)
|
||||
{
|
||||
console.log(props);
|
||||
|
||||
this.props.setFocusPosition([1,2])
|
||||
}
|
||||
|
||||
render() {
|
||||
const LocationFinderDummy = (props) => {
|
||||
const map = useMapEvents({
|
||||
click(e) {
|
||||
|
||||
props.props.setFocusPosition(e.latlng)
|
||||
// console.log(e.latlng);
|
||||
},
|
||||
});
|
||||
return null;
|
||||
};
|
||||
// const positions = this.props.Positions.map((pos, index) => (
|
||||
// <Marker name={"test"} key={index} position={pos.position} icon= {ship} />
|
||||
// ));
|
||||
|
||||
return (
|
||||
|
||||
<div className='map' style={{ height: this.state.height }} >
|
||||
<MapContainer center={[54, 11]} zoom={6} scrollWheelZoom={true} contextmenu={false}
|
||||
|
||||
>
|
||||
<LocationFinderDummy props ={this.props} />
|
||||
|
||||
<TileLayer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
|
||||
<TileLayer
|
||||
url="https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png" />
|
||||
{/* {positions} */}
|
||||
{this.props.Entities.map((pos, index) => (
|
||||
this.makeIcon(index,pos,this.props,this.state)
|
||||
))}
|
||||
</MapContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default OpenSeaMap;
|
||||
@@ -0,0 +1,23 @@
|
||||
@import 'leaflet/dist/leaflet.css';
|
||||
|
||||
// @import url('https://unpkg.com/leaflet@1.5.1/dist/leaflet.css');
|
||||
.leaflet-container {
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
|
||||
.map {
|
||||
// display: flex;
|
||||
padding-top: 10px;
|
||||
// height: 750px;
|
||||
width: 72%;
|
||||
// padding-left: 20%;
|
||||
display: inline-flex;
|
||||
// height: 80%;
|
||||
}
|
||||
|
||||
// .leaflet-marker-icon{
|
||||
// background: red;
|
||||
|
||||
// }
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Icon} from 'leaflet';
|
||||
import ms from 'milsymbol'
|
||||
|
||||
const iconShip = new Icon({
|
||||
iconUrl: "./ship.svg",
|
||||
iconSize: [50, 50],
|
||||
// iconAnchor: [40, 90],
|
||||
popupAnchor: [-25, -40],
|
||||
});
|
||||
|
||||
const HostileLetter = "H";
|
||||
const FriendLetter = "F";
|
||||
const NeutralLetter = "N";
|
||||
|
||||
const AirLetter = "A";
|
||||
const SurfaceLetter = "S";
|
||||
const SubsurfaceLetter = "U";
|
||||
|
||||
// const Size = 25;
|
||||
|
||||
function createIcon(Type , Side )
|
||||
{
|
||||
var TypeLetter = "S";
|
||||
var SideLetter = "N";
|
||||
switch (Side) {
|
||||
case "Hostile":
|
||||
SideLetter = HostileLetter;
|
||||
break;
|
||||
case "Friend":
|
||||
SideLetter = FriendLetter;
|
||||
break;
|
||||
case "Neutral":
|
||||
SideLetter = NeutralLetter;
|
||||
break;
|
||||
|
||||
default:
|
||||
SideLetter = "N";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Type) {
|
||||
case "Air":
|
||||
TypeLetter = AirLetter;
|
||||
break;
|
||||
case "Surface":
|
||||
TypeLetter = SurfaceLetter;
|
||||
break;
|
||||
case "Subsurface":
|
||||
TypeLetter = SubsurfaceLetter;
|
||||
break;
|
||||
|
||||
default:
|
||||
TypeLetter = "S";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var IconS = new ms.Symbol(
|
||||
"S"+SideLetter+TypeLetter+"*"+"--------"
|
||||
)
|
||||
IconS = IconS.setOptions({ size: 25 });
|
||||
|
||||
var Symbol = new Icon({
|
||||
iconUrl: IconS.toDataURL(),
|
||||
iconAnchor: [IconS.getAnchor().x, IconS.getAnchor().y],
|
||||
})
|
||||
|
||||
return Symbol
|
||||
}
|
||||
|
||||
var Friend = new ms.Symbol(
|
||||
"SFS*--------", {
|
||||
// uniqueDesignation: "Friend"
|
||||
})
|
||||
// Now that we have a symbol we can ask for the echelon and set the symbol size
|
||||
Friend = Friend.setOptions({ size: 25 });
|
||||
|
||||
const friend = new Icon({
|
||||
iconUrl: Friend.toDataURL(),
|
||||
iconAnchor: [Friend.getAnchor().x, Friend.getAnchor().y],
|
||||
});
|
||||
|
||||
|
||||
var hostile = new ms.Symbol(
|
||||
"SHU*---------", {
|
||||
uniqueDesignation: "Hostile"
|
||||
})
|
||||
// Now that we have a symbol we can ask for the echelon and set the symbol size
|
||||
hostile = hostile.setOptions({ size: 25 });
|
||||
|
||||
const Hostile = new Icon({
|
||||
iconUrl: hostile.toDataURL(),
|
||||
iconAnchor: [hostile.getAnchor().x, hostile.getAnchor().y],
|
||||
});
|
||||
|
||||
export { iconShip, friend,Hostile,createIcon };
|
||||
@@ -0,0 +1,392 @@
|
||||
import React from "react"
|
||||
import {useState,useEffect, useRef} from 'react';
|
||||
import { useForm, SubmitHandler } from "react-hook-form"
|
||||
import Form from 'react-bootstrap/Form';
|
||||
import FloatingLabel from 'react-bootstrap/FloatingLabel';
|
||||
import InputGroup from 'react-bootstrap/InputGroup';
|
||||
import round from "../../../Utils";
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
|
||||
import './controls.css'
|
||||
|
||||
|
||||
|
||||
function EntityControl(props)
|
||||
{
|
||||
const RoundPrecision = 2;
|
||||
const RoundPrecisionPosition = 4;
|
||||
|
||||
|
||||
const [Entity, setEntity] = useState(undefined);
|
||||
|
||||
// const [Course, setCourse] = useState('');
|
||||
const [PositionDragged, setPositionDragged] = useState(false);
|
||||
// const [Speed, setSpeed] = useState();
|
||||
|
||||
const [formData, setFormData] = useState({name: "",course: 0 ,speed: 0,position: [0,0],height:0});
|
||||
|
||||
|
||||
|
||||
useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`;
|
||||
|
||||
// console.log(props.Entity);
|
||||
|
||||
if(props.Entity !== undefined)
|
||||
{
|
||||
// console.log(props.Entity)
|
||||
if(Entity === undefined)
|
||||
{
|
||||
setEntity(props.Entity);
|
||||
setFormData({name:props.Entity.Name,course:props.Entity.Course,speed:props.Entity.Speed,position:props.Entity.Position,height:round(props.Entity.Height,RoundPrecision) })
|
||||
|
||||
}else if(Entity.id !== props.Entity.id)
|
||||
{
|
||||
setEntity(props.Entity);
|
||||
setFormData({name:props.Entity.Name,course:props.Entity.Course,speed:props.Entity.Speed,position:props.Entity.Position,height:round(props.Entity.Height,RoundPrecision)})
|
||||
|
||||
} else if(Entity.id === props.Entity.id && Entity.Position !== props.Entity.Position)
|
||||
{
|
||||
setFormData({...formData,position:props.Entity.Position,height:round(props.Entity.Height,RoundPrecision)})
|
||||
setPositionDragged(true);
|
||||
|
||||
|
||||
}
|
||||
// setFormData({name:props.Entity.Name,course:props.Entity.Course,speed:props.Entity.Speed,position:props.Entity.Position})
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
},[props.Entity,props]);
|
||||
|
||||
useEffect(() => {
|
||||
if(props.PositionCliecked !== undefined)
|
||||
{
|
||||
console.log(props.PositionCliecked)
|
||||
var pos = [0,0];
|
||||
pos[0] = props.PositionCliecked.lat;
|
||||
pos[1] = props.PositionCliecked.lng
|
||||
setFormData({...formData,position:pos});
|
||||
}
|
||||
|
||||
},[props.PositionCliecked])
|
||||
|
||||
|
||||
|
||||
|
||||
// Entity.Entity.Course
|
||||
const handleClick = (e) => {
|
||||
if(e.detail === 2)
|
||||
{
|
||||
console.log(e)
|
||||
// setCourseInControl(true);
|
||||
e.target.readOnly = false;
|
||||
// e.target.style = "border: 1px solid"
|
||||
}
|
||||
};
|
||||
|
||||
const handleCourseInput= (e) => {
|
||||
// console.log(e.currentTarget.value)
|
||||
// console.log(isNaN(e.nativeEvent?.data))
|
||||
// if(!isNaN(e.nativeEvent?.data))
|
||||
if(Number.isInteger(parseFloat(e.currentTarget.value)) | e.nativeEvent?.data === null )
|
||||
{
|
||||
setFormData({...formData,course:e.currentTarget.value});
|
||||
if(props.Entity !== undefined)
|
||||
{
|
||||
props.Entity.Course = e.currentTarget.value.replace(",",".");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if(e.currentTarget.value === "")
|
||||
// {
|
||||
// setFormData({...formData,course:0});
|
||||
// props.Entity.Course = 0;
|
||||
|
||||
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSpeedInput= (e) => {
|
||||
// console.log(e.nativeEvent?.data)
|
||||
// if(!isNaN(e.nativeEvent?.data))
|
||||
if(Number.isInteger(parseFloat(e.currentTarget.value)) | e.nativeEvent?.data === null )
|
||||
{
|
||||
|
||||
setFormData({...formData,speed:e.currentTarget.value});
|
||||
if(props.Entity !== undefined)
|
||||
{
|
||||
props.Entity.Speed = e.currentTarget.value.replace(",",".");
|
||||
}
|
||||
|
||||
}
|
||||
// if(e.nativeEvent?.data == null)
|
||||
// {
|
||||
// setFormData({...formData,speed:0});
|
||||
// props.Entity.Speed = 0;
|
||||
|
||||
|
||||
// }
|
||||
|
||||
// console.log(formData.speed)
|
||||
};
|
||||
|
||||
const handleNameInput = (e) => {
|
||||
setFormData({...formData,name:e.currentTarget.value});
|
||||
|
||||
}
|
||||
|
||||
|
||||
const handleInput = (e) => {
|
||||
// console.log(e.target.name)
|
||||
switch (e.target.name) {
|
||||
case "Lat":
|
||||
|
||||
if(Number.isInteger(parseFloat(e.currentTarget.value)) | e.nativeEvent?.data === null)
|
||||
{
|
||||
// e.currentTarget.value = e.currentTarget.value.replace(",",".");
|
||||
setFormData({...formData,position:[e.currentTarget.value,formData.position[1],formData.position[2]] });
|
||||
}
|
||||
if(props.Entity !== undefined)
|
||||
{
|
||||
props.Entity.Position[0]=e.currentTarget.value.replace(",",".");
|
||||
}
|
||||
break;
|
||||
case "Lon":
|
||||
if(Number.isInteger(parseFloat(e.currentTarget.value)) | e.nativeEvent?.data === null)
|
||||
{
|
||||
|
||||
setFormData({...formData,position:[formData.position[0],e.currentTarget.value,formData.position[2]] });
|
||||
if(props.Entity !== undefined)
|
||||
{
|
||||
props.Entity.Position[1]=e.currentTarget.value.replace(",",".");
|
||||
}
|
||||
|
||||
}
|
||||
// else if(e.nativeEvent?.data == null) {
|
||||
// // setFormData({...formData,position:[formData.position[0],0,formData.position[2]] });
|
||||
|
||||
// }
|
||||
|
||||
|
||||
break;
|
||||
case "Height":
|
||||
setFormData({...formData,height:e.currentTarget.value.replace(",",".")});
|
||||
if(props.Entity !== undefined)
|
||||
{
|
||||
props.Entity.Height=e.currentTarget.value.replace(",",".");
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
setPositionDragged(true);
|
||||
}
|
||||
|
||||
const emptyForm= (e) =>
|
||||
{
|
||||
if(props.Entity !== undefined)
|
||||
{
|
||||
props.Entity.onFocus = undefined;
|
||||
}
|
||||
setFormData({name:'',course:0,speed:0,position:[0,0],height:0})
|
||||
setEntity(undefined)
|
||||
props.Functions.resetEntityOnFocus();
|
||||
|
||||
}
|
||||
|
||||
const resetForm = (e)=>
|
||||
{
|
||||
if(props.Entity !== undefined)
|
||||
{
|
||||
console.log("resetting")
|
||||
setFormData({name:props.Entity.Name,course:Entity.Course,speed:Entity.Speed,position:Entity.Position})
|
||||
props.Entity.Position = Entity.Position;
|
||||
props.Entity.Course = Entity.Course;
|
||||
props.Entity.Speed = Entity.Speed;
|
||||
}
|
||||
else {
|
||||
emptyForm();
|
||||
}
|
||||
}
|
||||
|
||||
// const handleChange = (event) => {
|
||||
// const { name, value } = event.target;
|
||||
// setFormData((prevFormData) => ({ ...prevFormData, [name]: value }));
|
||||
// };
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
// console.log(e.target.data);
|
||||
// console.log(formData)
|
||||
console.log(Entity)
|
||||
if(Entity === undefined)
|
||||
{
|
||||
var msg =
|
||||
{
|
||||
Data: "Entity",
|
||||
Type: "New",
|
||||
Name: formData.name,
|
||||
Speed: formData.speed.toString(),
|
||||
Course: formData.course.toString(),
|
||||
Position: [formData.position[0].toString(),formData.position[1].toString()],
|
||||
Height: formData.height.toString(),
|
||||
SetPosition: true
|
||||
|
||||
}
|
||||
|
||||
}else {
|
||||
var setPos;
|
||||
if(PositionDragged === true)
|
||||
{
|
||||
setPos = true;
|
||||
}else{
|
||||
setPos = false;
|
||||
}
|
||||
|
||||
var msg =
|
||||
{
|
||||
Data: "Entity",
|
||||
Type: "Update",
|
||||
ID: Entity.id,
|
||||
Speed: formData.speed.toString(),
|
||||
Course: formData.course.toString(),
|
||||
Position: [formData.position[0].toString(),formData.position[1].toString()],
|
||||
Height: formData.height.toString(),
|
||||
SetPosition: setPos
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
console.log(JSON.stringify(msg));
|
||||
|
||||
props.Client.send(JSON.stringify(msg));
|
||||
// alert(`Course: ${formData.course}`);
|
||||
}
|
||||
// console.log(Entity)
|
||||
// console.log(EntityOnFocus)
|
||||
return (
|
||||
|
||||
<div>
|
||||
<div><button onClick={ emptyForm}> New</button> </div>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="ControlsComponent">
|
||||
<div class="parent">
|
||||
<div class="div1">
|
||||
<div className="ControlLineHeader">
|
||||
|
||||
<InputGroup className="mb-3">
|
||||
<InputGroup.Text id="basic-addon1">Kind</InputGroup.Text>
|
||||
<Form.Select name="Kind" size="sm" >
|
||||
<option selected value="plattform"> Plattform</option>
|
||||
</Form.Select>
|
||||
</InputGroup>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="div2">
|
||||
<div className="ControlLineHeader">
|
||||
{/* <div className="LineHeader">Domain:</div>
|
||||
<select name="domain">
|
||||
<option name="surface">Surface</option>
|
||||
|
||||
</select> */}
|
||||
|
||||
<InputGroup className="mb-3">
|
||||
<InputGroup.Text id="basic-addon1">Domain</InputGroup.Text>
|
||||
<Form.Select name="Domain" >
|
||||
<option selected value="Surface"> Surface</option>
|
||||
</Form.Select>
|
||||
</InputGroup>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="div3">
|
||||
<InputGroup className="mb-3">
|
||||
<InputGroup.Text id="basic-addon1">Type</InputGroup.Text>
|
||||
<Form.Select name="Domain" >
|
||||
<option selected value="F124"> F124</option>
|
||||
</Form.Select>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<div class="div4">
|
||||
<InputGroup className="mb-3">
|
||||
<InputGroup.Text id="basic-addon1">Name</InputGroup.Text>
|
||||
<Form.Control
|
||||
name="Name"
|
||||
placeholder="Name"
|
||||
aria-label="Name"
|
||||
aria-describedby="basic-addon1"
|
||||
value={formData.name}
|
||||
onChange={handleNameInput}
|
||||
/>
|
||||
{/* <input name="Name" type="text" onChange={handleNameInput} value={formData.name} /> */}
|
||||
</InputGroup>
|
||||
|
||||
{/* <div class="NameInput">
|
||||
<div className="ControlLineHeader">Name:</div>
|
||||
</div> */}
|
||||
|
||||
</div>
|
||||
<div class="div5">
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text">Course</span>
|
||||
<input className="EntityinputField" name="Course" readOnly={false} type="text" onClick={handleClick} onChange={handleCourseInput} value={formData.course} />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="div6">
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text">Speed</span>
|
||||
<input className="EntityinputField" name="Speed" onChange={handleSpeedInput} value={formData.speed} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="div7">
|
||||
<div class="input-group mb-3 NumberInputsGroup">
|
||||
<span class="input-group-text">Lat</span>
|
||||
<input className="ControlInput NumberInputs" name="Lat" type="text" onChange={handleInput} value={round(formData.position[0],RoundPrecisionPosition)} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="div8">
|
||||
<div class="input-group mb-3 NumberInputsGroup" >
|
||||
<span class="input-group-text">Lon</span>
|
||||
{/* <input className="ControlInput" name="Lat" readOnly={true} type="text" onClick={handleClick} value={formData.position[0]} /> */}
|
||||
<input className="ControlInput NumberInputs" name="Lon" readOnly={true} type="text" onClick={handleClick} onChange={handleInput} value={round(formData.position[1],RoundPrecisionPosition)}/>
|
||||
</div>
|
||||
{/* <div className="flex">
|
||||
<div className="ControlHeader">Lon:</div>
|
||||
</div> */}
|
||||
</div>
|
||||
<div class="div9">
|
||||
<div class="input-group mb-3 NumberInputsGroup">
|
||||
<span class="input-group-text">Height</span>
|
||||
{/* <input className="ControlInput" name="Lat" readOnly={true} type="text" onClick={handleClick} value={formData.position[0]} /> */}
|
||||
<input className="ControlInput NumberInputs" name="Height" readOnly={true} type="text" onClick={handleClick} onChange={handleInput} value={formData.height}/>
|
||||
</div>
|
||||
{/* <div className="ControlHeader">Height:</div>
|
||||
<div className="flex">
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div> <button type='submit'>Save</button> </div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
<button onClick={resetForm}> RESET</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EntityControl;
|
||||
@@ -0,0 +1,3 @@
|
||||
import Tracklist from "./tracklist.jsx";
|
||||
|
||||
export default Tracklist;
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import './tracklist.scss'
|
||||
import round from '../../../../Utils';
|
||||
|
||||
|
||||
|
||||
class Tracklist extends React.Component
|
||||
{
|
||||
|
||||
render()
|
||||
{
|
||||
|
||||
return(
|
||||
<div className="tracklist">
|
||||
<table>
|
||||
<thead>
|
||||
<tr className='TracklistHeader'>
|
||||
<th className='TracklistHeaderCell'>Name</th>
|
||||
<th className='TracklistHeaderCell'>Course</th>
|
||||
<th className='TracklistHeaderCell'>Speed</th>
|
||||
<th className='TracklistHeaderCell'>Lat</th>
|
||||
<th className='TracklistHeaderCell'>Lon</th>
|
||||
<th className='TracklistHeaderCell'>Kind</th>
|
||||
<th className='TracklistHeaderCell'>Side</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ this.props.entities.map((val,index) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
<td >{val.Name}</td>
|
||||
<td className='TracklistCell'>{val.Course}</td>
|
||||
<td className='TracklistCell'>{val.Speed}</td>
|
||||
<td className='TracklistCell'>{round(val.Position[0],4)}</td>
|
||||
<td className='TracklistCell'>{round(val.Position[1],4)}</td>
|
||||
<td className='TracklistCell'>{val.Type}</td>
|
||||
<td className='TracklistCell'>{val.Side}</td>
|
||||
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Tracklist;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
.tracklist
|
||||
{
|
||||
display: flex;
|
||||
max-height: 40%;
|
||||
height: 300px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
td
|
||||
{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.TracklistHeader {
|
||||
border-bottom: 2px solid;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th{
|
||||
// border: 1px solid;
|
||||
// border-collapse: collapse;
|
||||
}
|
||||
|
||||
.TracklistCell{
|
||||
border-left: 1px solid;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.TracklistHeaderCell{
|
||||
width: 16%;
|
||||
}
|
||||
|
||||
|
||||
// table, th, td {
|
||||
// border: 1px solid;
|
||||
// border-collapse: collapse;
|
||||
// }
|
||||
@@ -0,0 +1,91 @@
|
||||
.controls{
|
||||
/* display: flex; */
|
||||
width: 24%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.ControlsComponent{
|
||||
display: grid;
|
||||
/* grid-template-columns: auto auto auto; */
|
||||
}
|
||||
.ControlInput{
|
||||
/* border: none; */
|
||||
width: 30%;
|
||||
}
|
||||
.NameInput{
|
||||
/* margin: 0 auto; */
|
||||
display: flex;
|
||||
}
|
||||
.EntityinputField{
|
||||
/* border: none; */
|
||||
width: 30%;
|
||||
display: flex;
|
||||
}
|
||||
.flex{
|
||||
display: flex !important;
|
||||
|
||||
}
|
||||
|
||||
.ControlHeader{
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
.ControlLineHeader
|
||||
{
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
.LineHeader{
|
||||
display: flex;
|
||||
float: left;
|
||||
}
|
||||
.sizedSelect{
|
||||
width: 50% !important;
|
||||
}
|
||||
|
||||
.NumberInputs{
|
||||
width: 4.3em;
|
||||
}
|
||||
.NumberInputsGroup
|
||||
{
|
||||
flex-wrap: inherit !important;
|
||||
}
|
||||
|
||||
.ControlValues{
|
||||
float: left;
|
||||
display: contents;
|
||||
}
|
||||
|
||||
/* .parent {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-template-rows: repeat(3 2em);
|
||||
grid-column-gap: 0px;
|
||||
grid-row-gap: 0px;
|
||||
}
|
||||
|
||||
.div1 { grid-area: 1 / 1 / 2 / 3; }
|
||||
.div2 { grid-area: 2 / 1 / 3 / 2; }
|
||||
.div3 { grid-area: 2 / 2 / 3 / 3; }
|
||||
.div4 { grid-area: 3 / 2 / 4 / 3; }
|
||||
.div5 { grid-area: 3 / 1 / 4 / 2; } */
|
||||
|
||||
|
||||
.parent {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 2fr);
|
||||
grid-template-rows: repeat(6, 3em);
|
||||
grid-column-gap: 0px;
|
||||
grid-row-gap: 0px3
|
||||
}
|
||||
|
||||
.div1 { grid-area: 1 / 1 / 2 / 4; }
|
||||
.div2 { grid-area: 2 / 1 / 3 / 4; }
|
||||
.div3 { grid-area: 3 / 1 / 4 / 4; }
|
||||
.div4 { grid-area: 4 / 1 / 5 / 4; }
|
||||
.div5 { grid-area: 5 / 1 / 6 / 2; }
|
||||
.div6 { grid-area: 5 / 2 / 6 / 3; }
|
||||
.div7 { grid-area: 6 / 1 / 7 / 2; }
|
||||
.div8 { grid-area: 6 / 2 / 7 / 3; }
|
||||
.div9 { grid-area: 6 / 3 / 7 / 4; }
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import React from 'react';
|
||||
import './controls.css'
|
||||
// import { sendMsg } from '../api';
|
||||
import Tracklist from './Tracklist'
|
||||
import EntityControl from './EntityControl';
|
||||
import round from '../../../Utils';
|
||||
// import {w3cwebsocket as W3CWebSocket} from "websocket"
|
||||
|
||||
|
||||
|
||||
class Controls extends React.Component
|
||||
{
|
||||
|
||||
state = {
|
||||
EntityOnFocus: undefined,
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
|
||||
if (this.props.Entities === undefined)
|
||||
{
|
||||
this.props.Entities = new Array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
function getEntityFromID(Entities, SelectedEntity)
|
||||
{
|
||||
if(SelectedEntity !== undefined)
|
||||
{
|
||||
var tmp = {};
|
||||
// tmp.NewPos= new Array(0,0);
|
||||
// console.log(tmp);
|
||||
|
||||
Entities.map((val) => {
|
||||
if(val.id === SelectedEntity.EntityID)
|
||||
{
|
||||
tmp = val
|
||||
// tmp = JSON.parse(JSON.stringify(val));
|
||||
// console.log(tmp);
|
||||
val.dragged = SelectedEntity.dragged;
|
||||
if(SelectedEntity.dragged === undefined)
|
||||
{
|
||||
val.dragged = false;
|
||||
}
|
||||
|
||||
// console.log(SelectedEntity);
|
||||
|
||||
// if(SelectedEntity.NewPos !== undefined)
|
||||
// {
|
||||
// // Object.assign(tmp, {NewPos: [{},{}]});
|
||||
// Object.assign(val, {NewPos: [{},{}]});
|
||||
|
||||
// // tmp.OldPos = val.Position;
|
||||
// // Object.assign(tmp, {NewPos: [round(SelectedEntity.NewPos[0],3),0]});
|
||||
// // val.NewPos = SelectedEntity.NewPos;
|
||||
// val.NewPos[0] = round(SelectedEntity.NewPos[0],3);
|
||||
// val.NewPos[1] = round(SelectedEntity.NewPos[1],3);
|
||||
|
||||
// // tmp.NewPos[0] = round(SelectedEntity.NewPos[0],3);
|
||||
// // tmp.NewPos[1] = round(SelectedEntity.NewPos[1],3);
|
||||
|
||||
// }
|
||||
|
||||
// tmp.NewPos = SelectedEntity.NewPos;
|
||||
}
|
||||
return tmp;
|
||||
})
|
||||
// console.log(tmp);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// console.log(getEntityFromID(this.props.Entities,this.props.EntityOnFocus));
|
||||
return (
|
||||
<div className="controls">
|
||||
<Tracklist entities= {this.props.Entities} />
|
||||
<br />
|
||||
<div>
|
||||
{/* <button onClick={this.props.updateEntities}>update</button> */}
|
||||
<EntityControl Functions = {this.props.Functions} Client = { this.props.Client } Entity = { getEntityFromID(this.props.Entities,this.props.EntityOnFocus)} EntityOnFocus= {this.props.EntityOnFocus} PositionCliecked = {this.props.PositionClicked}/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Controls;
|
||||
@@ -0,0 +1,3 @@
|
||||
import Controls from "./controls.jsx";
|
||||
|
||||
export default Controls;
|
||||
@@ -0,0 +1,4 @@
|
||||
.map
|
||||
{
|
||||
width: 70%;
|
||||
}
|
||||
16
webapp/src/components/SimControl/components/map/mapframe.js
Normal file
16
webapp/src/components/SimControl/components/map/mapframe.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import './mapframe.css'
|
||||
|
||||
class Mapframe extends React.Component
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<div className="map">
|
||||
this is the map frame
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Mapframe;
|
||||
3
webapp/src/components/SimControl/index.js
Normal file
3
webapp/src/components/SimControl/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import SimControl from "./SimControl.jsx";
|
||||
|
||||
export default SimControl;
|
||||
Reference in New Issue
Block a user