Files
qt5-legatus-legacy/Lts/Tools/TrackingTool/script.js
T
2026-08-13 18:33:10 +02:00

339 lines
14 KiB
JavaScript
Executable File

import { Equipment } from "./EquipmentClass.js";
import { paintIt } from "./Helpers.js";
import * as mapLayers from "./Map.js";
var exercises = {};
var participantBaseData = {};
var partyBaseData = {};
var parties = {}; //Ersatzobjekt statt 'equipments'-Map
popup();
document.getElementById('connectStaticBtn').addEventListener ('click', webSocketConnectStatic);
document.getElementById('connectDynamicBtn').addEventListener ('click', webSocketConnectDynamic);
// Map
var map = L.map('content-map', {
layers: [mapLayers.OpenStreetMap_Mapnik], // only add one!
zoomControl: false
})
.setView([53.055311, 8.896582], 16);
var baseLayers = {
"Gelände": mapLayers.OpenStreetMap_Mapnik,
"Sattelit": mapLayers.Esri_WorldImagery
};
var overlays = {
"Katar": mapLayers.KatarGeoJSON
}
L.control.layers(baseLayers, overlays).addTo(map);
L.control.zoom({position: 'bottomright'}).addTo(map);
// WebSocket Static Port
function webSocketConnectStatic() {
var ws = new WebSocket (document.getElementById('connectInput').value);
ws.onopen = function () {
document.getElementById('connectStaticBtn').classList.replace("btn-outline-danger", "btn-outline-success")
servicePortsInformationRequest(ws);
}
ws.onmessage = function(msg) {
var object = (JSON.parse(msg.data)).data;
object.forEach((item, index, array) => {
if (item.exerciseId != 0) {
exercises[item.exerciseId] = item;
document.getElementById('exerciseSelect').innerHTML += `<option value=${item.exerciseId}>Exercise ${item.exerciseId}</option>`
}
})
document.getElementById('exerciseSelect').disabled = false;
document.getElementById('connectDynamicBtn').disabled = false;
}
ws.onclose = function() {
document.getElementById('connectStaticBtn').classList.replace("btn-outline-success", "btn-outline-danger")
}
}
// WebSocket Dynamic Port
function webSocketConnectDynamic() {
var exerciseId = parseInt(document.getElementById("exerciseSelect").value);
var dynamicPort1 = exercises[exerciseId].services[0].ports[1].number; //Objekt-Pfad zum dynamischen Port, der Teilnehmerinfos enthaelt.
var dynamicPort2 = exercises[exerciseId].services[0].ports[0].number; //Objekt-Pfad zum dynamischen Port, der Positionsdaten empfaengt.
var wsPort2 = new WebSocket (`ws://localhost:${dynamicPort2}`);
// Positionsdaten empfangen (PortId 2)
wsPort2.onopen = function () {
document.getElementById('connectDynamicBtn').classList.replace("btn-outline-danger", "btn-outline-success")
window.setTimeout(popdown, 1000);
}
wsPort2.onmessage = function(msg) {
processEquipment(msg);
}
wsPort2.onclose = function() {
document.getElementById('connectDynamicBtn').classList.replace("btn-outline-success", "btn-outline-danger")
}
// einmalig Participant-Informationen abfragen (PortId 1)
var wsPort1 = new WebSocket (`ws://localhost:${dynamicPort1}`);
wsPort1.onopen = function () {
BaseDlRequest(wsPort1);
}
wsPort1.onmessage = function (msg) {
if (JSON.parse(msg.data).type == "partyBaseData") {
JSON.parse(msg.data).data.forEach (partyInfo => {
partyBaseData[partyInfo.id] = partyInfo; //Objekt
})
}
if (JSON.parse(msg.data).type == "participantBaseData") {
JSON.parse(msg.data).data.forEach (participantInfo => {
if (!participantInfo.equipmentNumber == 0) { //unsausgesattete Teilnehmer (= EquipNr 0) ignorieren
participantBaseData[participantInfo.equipmentNumber] = participantInfo;
}
})
}
}
}
/* Equipment-Informationen verarbeiten aus Positionsmeldung durch WebSocket*/
function processEquipment(msg) {
var equipmentNumber = JSON.parse(msg.data).equipmentNumber;
var height = JSON.parse(msg.data).height;
var lat = JSON.parse(msg.data).lat;
var lon = JSON.parse(msg.data).lon;
var participantId = JSON.parse(msg.data).participantId;
var partyId = participantBaseData[equipmentNumber].partyId;
var eq = null;
//PartyId anzeigen: Accordion und LayerGroup
if (!parties.hasOwnProperty(partyId)) {
var partyName = partyBaseData[partyId].name;
var partyColor = paintIt(partyBaseData[partyId].color);
var partyContainer = document.getElementById('accordionParty');
var partyDiv = document.createElement('div');
partyDiv.id = `item-${partyId}`
partyDiv.classList.add('border-bottom')
partyDiv.innerHTML = `<h2 class="accordion-header" id="heading${equipmentNumber}">
<button id="button-${partyId}" class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse${equipmentNumber}" aria-expanded="true" aria-controls="collapse${equipmentNumber}">
${partyName}
</button>
<a id="hide-party-${partyId}" class="hide-party" href="#" data-bs-toggle="collapse">
<img id = "party-icon-${partyId}" src="./res/eye.svg">
</a>
</h2>
<div id="collapse${equipmentNumber}" class="accordion-collapse collapse show" aria-labelledby="heading${equipmentNumber}">
<div id="accordion-body-${partyId}" class="accordion-body p-0">
<table class="table table-hover table-condensed">
<tbody id="table-${partyId}">
</tbody>
</table>
</div>
</div>`
partyContainer.appendChild(partyDiv);
document.getElementById(`button-${partyId}`).style.color = partyColor
parties[partyId] = {
equipments: {},
layerGroup: L.layerGroup(),
partyName: partyName,
partyColor: partyColor,
tracked: true,
visible: true,
followedEquipment: null
}
// Show / Hide Party
document.getElementById(`hide-party-${partyId}`).addEventListener('click', () => {
if (!parties[partyId].visible) {
for (var key in parties[partyId].equipments) {
if (!parties[partyId].equipments[key].visible) {
parties[partyId].equipments[key].toggleMarkerVisibility(map)
}
}
parties[partyId].visible = true;
document.getElementById(`party-icon-${partyId}`).src = `./res/eye.svg`;
}
else {
for (var key in parties[partyId].equipments) {
if (parties[partyId].equipments[key].visible) {
parties[partyId].equipments[key].toggleMarkerVisibility(map);
}
}
parties[partyId].visible = false;
document.getElementById(`party-icon-${partyId}`).src = `./res/eye-slash.svg`;
}
});
}
//Equipment-Instanz im Party-Objekt anlegen
if (!parties[partyId].equipments.hasOwnProperty(equipmentNumber)) {
parties[partyId].equipments[equipmentNumber] = new Equipment(equipmentNumber, height, lat, lon, participantId);
parties[partyId].equipments[equipmentNumber].setPartyId(partyId);
parties[partyId].equipments[equipmentNumber].setDesignator(participantBaseData[equipmentNumber].designator);
parties[partyId].equipments[equipmentNumber].setTatcicalIdentifier(participantBaseData[equipmentNumber].tacticalIdentifier);
parties[partyId].equipments[equipmentNumber].setPartyColor(parties[partyId].partyColor);
}
//Equipment-Position aktualisieren
else {
parties[partyId].equipments[equipmentNumber].updatePosition(height, lat, lon);
if (parties.followedEquipment == equipmentNumber) {
parties[partyId].equipments[equipmentNumber].followMarker(map);
}
}
eq = parties[partyId].equipments[equipmentNumber];
//Equipment anzeigen: Accordion-Item und Marker (sortiert einfuegen)
if (!eq.tracked) {
var equipmentTable = document.getElementById(`table-${eq.getPartyId()}`)
var equipmentRow = document.createElement('tr');
equipmentRow.id = `${eq.equipmentNr}`; //ID ist EquipmentNr
var equipmentNrCell = document.createElement('td');
equipmentNrCell.style.paddingLeft = "1.25rem";
equipmentNrCell.innerHTML = `<a id ="focus-${eq.equipmentNr}" href = "#">${eq.equipmentNr}</a>`
var participantIdCell = document.createElement('td');
participantIdCell.innerHTML = `Participant ${eq.participantId}`;
var followCell = document.createElement('td');
followCell.style = "text-align:right";
followCell.style.width = "50px";
followCell.innerHTML = `<a id ="follow-${eq.equipmentNr}" href = "#"><img id="follow-icon-${eq.equipmentNr}" src="./res/crosshair_light.svg"></a>`;
var hideCell = document.createElement('td');
hideCell.style = "text-align:right";
hideCell.style.width = "50px";
hideCell.style.paddingRight = "1.25rem";
hideCell.innerHTML = `<a id ="visibility-${eq.equipmentNr}" href = "#"><img id="icon-${eq.equipmentNr}" src="./res/eye.svg"></a>`;
equipmentRow.append(equipmentNrCell);
equipmentRow.append(participantIdCell);
equipmentRow.append(followCell);
equipmentRow.append(hideCell);
breakme: if (equipmentTable.children.length > 0){ // Nach EquipmentID in Liste einsortieren
var children = equipmentTable.children;
for(var i=0; i<children.length; i++){
if (children[i].id > eq.equipmentNr) {
equipmentTable.insertBefore(equipmentRow,children[i]);
break breakme;
}
else {
equipmentTable.append(equipmentRow);
}
}
}
else {
equipmentTable.append(equipmentRow);
}
// Show / Hide
document.getElementById(`visibility-${eq.equipmentNr}`).addEventListener('click', () => {
eq.toggleMarkerVisibility(map);
var allHidden = true
for (var key in parties[partyId].equipments) {
if (parties[partyId].equipments[key].visible){
allHidden = false;
}
}
if (allHidden) {
parties[partyId].visible = false;
document.getElementById(`party-icon-${partyId}`).src = `./res/eye-slash.svg`;
}
else {
parties[partyId].visible = true;
document.getElementById(`party-icon-${partyId}`).src = `./res/eye.svg`;
}
});
// Pan to
document.getElementById(`focus-${eq.equipmentNr}`).addEventListener('click', () => {
eq.focusMarker(map);
parties[partyId].visible = true;
document.getElementById(`party-icon-${partyId}`).src = `./res/eye.svg`;
});
// Follow
document.getElementById(`follow-${eq.equipmentNr}`).addEventListener('click', () => {
if (parties.followedEquipment != eq.equipmentNr) {
if (!parties.followedEquipment == 0) {
document.getElementById(`follow-icon-${parties.followedEquipment}`).src = `./res/crosshair_light.svg`;
}
parties[partyId].visible = true;
document.getElementById(`party-icon-${partyId}`).src = `./res/eye.svg`;
parties.followedEquipment = equipmentNumber;
eq.focusMarker(map);
document.getElementById(`svgIcon-${eq.equipmentNr}`).style.strokeWidth = 3;
document.getElementById(`follow-icon-${eq.equipmentNr}`).src = `./res/crosshair_dark.svg`;
document.getElementById('infoOverlay').hidden = false;
document.getElementById('infoOverlay').innerHTML = "Equipment <b>" + eq.equipmentNr + "</b> Lat: " + eq.getLatDeg().toFixed(5) + " Lon: " + eq.getLonDeg().toFixed(5) + " Height: " + eq.height.toFixed(2)
} else {
parties.followedEquipment = null;
document.getElementById(`svgIcon-${eq.equipmentNr}`).style.strokeWidth = 1;
document.getElementById(`follow-icon-${eq.equipmentNr}`).src = `./res/crosshair_light.svg`;
document.getElementById('infoOverlay').hidden = true;
}
})
eq.setMarker(); //Marker anlegen
var party = parties[eq.getPartyId()].layerGroup;
party.addLayer(eq.getMarker()).addTo(map); //Marker werden zur jeweiligen Layer-Group hinzugefuegt und auf map dargestellt
eq.tracked = true;
eq.visible = true;
}
else {
eq.resetLatLng(parties.followedEquipment);
}
}
/* HTML-Funktionalitaet */
// Modal
var modal = new bootstrap.Modal(document.getElementById('staticBackdrop'));
function popup() {
document.onreadystatechange = function () {
modal.show();
};
}
function popdown() {
modal.hide();
}
// Sidebar on Btn
const sidebarToggle = document.body.querySelector('#sidebarToggle');
if (sidebarToggle) {
sidebarToggle.addEventListener('click', event => {
event.preventDefault();
document.body.classList.toggle('sb-sidenav-toggled');
localStorage.setItem('sb|sidebar-toggle', document.body.classList.contains('sb-sidenav-toggled'));
setTimeout(function(){ map.invalidateSize({animate: true})}, 280)
});
}
// Request
function servicePortsInformationRequest(ws) {
ws.send(JSON.stringify({
type: "servicePortsInformationRequest",
uuid: "UUID"
}));
}
function BaseDlRequest(ws) {
ws.send(JSON.stringify({
type: "baseDlRequest",
uuid: "UUID"
}));
}