diff --git a/client/public/stylesheets/layout.css b/client/public/stylesheets/layout.css index 53a9863c..ed682be4 100644 --- a/client/public/stylesheets/layout.css +++ b/client/public/stylesheets/layout.css @@ -72,10 +72,14 @@ dl.ol-data-grid dd { margin-left: auto; } -.br-info[data-bearing][data-distance][data-distance-units]::after { +.br-info::after { content: attr( data-bearing ) '\00B0 / ' attr( data-distance ) attr( data-distance-units ); } +.br-info[data-message]::after { + content: attr( data-message ); +} + .coordinates::after { content: attr( data-dd ) "\00b0 " attr( data-mm ) "'" attr( data-ss ) "." attr( data-sss ) '"' attr( data-label ); } @@ -112,7 +116,7 @@ dl.ol-data-grid dd { } .ol-panel.ol-dialog { - padding:25px; + padding:20px; } .ol-dialog-close { @@ -138,6 +142,12 @@ dl.ol-data-grid dd { padding-top:15px; } +.ol-dialog.scrollable .ol-dialog-content { + overflow-y: auto; +} + + + .ol-checkbox label { align-items: center; cursor: pointer; diff --git a/client/public/stylesheets/mouseinfopanel.css b/client/public/stylesheets/mouseinfopanel.css index c571e514..fe8030a3 100644 --- a/client/public/stylesheets/mouseinfopanel.css +++ b/client/public/stylesheets/mouseinfopanel.css @@ -25,7 +25,7 @@ #mouse-info-panel dt { height:20px; - width:40%; + width:30%; } #mouse-info-panel dt::after { @@ -44,12 +44,20 @@ width:16px; } -#mouse-info-panel dt#ref-measure-position::after { +#mouse-info-panel dt#ref-unit-position::after { background-image: url( "/images/icons/ruler.svg" ); background-position: 50% 50%; background-repeat: no-repeat; background-size:16px 16px; - content: " "; + content: ""; +} + +#mouse-info-panel dt#ref-measure-position::after { + background-image: url( "/images/pin.png" ); + background-position: 50% 50%; + background-repeat: no-repeat; + background-size:16px 16px; + content: ""; } @@ -79,5 +87,5 @@ } #mouse-info-panel dd { - width:60%; + width:70%; } \ No newline at end of file diff --git a/client/public/stylesheets/olympus.css b/client/public/stylesheets/olympus.css index fb6e64c5..e6c3ed83 100644 --- a/client/public/stylesheets/olympus.css +++ b/client/public/stylesheets/olympus.css @@ -4,6 +4,7 @@ @import url("contextmenus.css"); @import url("mouseinfopanel.css"); @import url("units.css"); +@import url("unitdatatable.css"); @import url("unitcontrolpanel.css"); @import url("unitinfopanel.css"); diff --git a/client/public/stylesheets/unitdatatable.css b/client/public/stylesheets/unitdatatable.css new file mode 100644 index 00000000..f666ab25 --- /dev/null +++ b/client/public/stylesheets/unitdatatable.css @@ -0,0 +1,27 @@ +#unit-data-table { + display:flex; + flex-direction: column; + font-size:13px; + height: 250px; + width:fit-content; +} + +#unit-data-table > div { + display:flex; + flex-direction: row; + flex-wrap: nowrap; +} + +#unit-data-table > div > div { + text-overflow: ellipsis; + white-space: nowrap; + width:100px; +} + +#unit-data-table > div:first-of-type { + text-align: center; +} + +#unit-data-table > div > div:nth-of-type( 4 ) { + text-align: center; +} \ No newline at end of file diff --git a/client/src/index.ts b/client/src/index.ts index 130c3717..a16d03a5 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -10,6 +10,7 @@ import { ATC } from "./atc/atc"; import { FeatureSwitches } from "./featureswitches"; import { LogPanel } from "./panels/logpanel"; import { getAirbases, getBulllseye as getBulllseyes, getMission, getUnits, toggleDemoEnabled } from "./server/server"; +import { UnitDataTable } from "./units/unitdatatable"; var map: Map; @@ -29,6 +30,7 @@ var connected: boolean = false; var activeCoalition: string = "blue"; var sessionHash: string | null = null; +var unitDataTable = new UnitDataTable(); var featureSwitches; @@ -75,6 +77,7 @@ function setup() { startPeriodicUpdate(); } + function startPeriodicUpdate() { requestUpdate(); requestRefresh(); @@ -84,6 +87,7 @@ function requestUpdate() { /* Main update rate = 250ms is minimum time, equal to server update time. */ getUnits((data: UnitsData) => { getUnitsManager()?.update(data); + getUnitDataTable().update( data.units ) checkSessionHash(data.sessionHash); }, false); setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000); @@ -137,13 +141,21 @@ function setupEvents() { /* Keyup events */ document.addEventListener("keyup", ev => { + switch (ev.code) { + case "KeyL": document.body.toggleAttribute("data-hide-labels"); break; + case "KeyD": toggleDemoEnabled(); + break; + + case "Quote": + unitDataTable.toggle(); } + }); /* @@ -154,7 +166,6 @@ function setupEvents() { unitName.setAttribute( "readonly", "true" ); // Do something with this: - console.log( unitName.value ); }); document.addEventListener( "editUnitName", ev => { @@ -214,6 +225,10 @@ export function getMissionData() { return missionHandler; } +export function getUnitDataTable() { + return unitDataTable; +} + export function getUnitsManager() { return unitsManager; } diff --git a/client/src/panels/mouseinfopanel.ts b/client/src/panels/mouseinfopanel.ts index cd76e7d9..023ca085 100644 --- a/client/src/panels/mouseinfopanel.ts +++ b/client/src/panels/mouseinfopanel.ts @@ -72,6 +72,41 @@ export class MouseInfoPanel extends Panel { el.dataset.distanceUnits = "nm"; } } + + const refMouseLat = document.getElementById( "ref-mouse-position-latitude" ); + const mouseLat = document.getElementById( "mouse-position-latitude" ); + + if ( refMouseLat && mouseLat ) { + + let matches = String( mousePosition.lat ).match( /^\-?(\d+)\.(\d{2})(\d{2})(\d{2})/ ); + + if ( matches && matches.length ) { + mouseLat.dataset.dd = matches[1]; + mouseLat.dataset.mm = matches[2]; + mouseLat.dataset.ss = matches[3]; + mouseLat.dataset.sss = matches[4]; + } + + refMouseLat.dataset.label = ( mousePosition.lat < 0 ) ? "S" : "N"; + + } + + const refMouseLng = document.getElementById( "ref-mouse-position-longitude" ); + const mouseLng = document.getElementById( "mouse-position-longitude" ); + + if ( refMouseLng && mouseLng ) { + + let matches = String( mousePosition.lng ).match( /^\-?(\d+)\.(\d{2})(\d{2})(\d{2})/ ); + + if ( matches && matches.length ) { + mouseLng.dataset.dd = matches[1]; + mouseLng.dataset.mm = matches[2]; + mouseLng.dataset.ss = matches[3]; + mouseLng.dataset.sss = matches[4]; + } + + refMouseLng.dataset.label = ( mousePosition.lng < 0 ) ? "W" : "E"; + } } #onMapClick(e: any) @@ -155,13 +190,30 @@ export class MouseInfoPanel extends Panel { #onUnitsSelection(units: Unit[]) { - if (units.length == 1) - this.getElement().querySelector(`#unit-position`)?.classList.toggle("hide", false); + const pos = this.getElement().querySelector(`#unit-position`); + + if ( units.length > 1 ) { + pos?.setAttribute( "data-message", "(multiple units)" ); + } else { + pos?.removeAttribute( "data-message" ); + } + } #onClearSelection() { this.#measureBox.classList.toggle("hide", true); - this.getElement().querySelector(`#unit-position`)?.classList.toggle("hide", true); + + const pos = this.getElement().querySelector(`#unit-position`); + + + if ( pos instanceof HTMLElement ) { + pos?.removeAttribute( "data-message" ); + + pos.dataset.bearing = "---"; + pos.dataset.distance = "---"; + pos.dataset.distanceUnits = "nm"; + + } } } diff --git a/client/src/units/unit.ts b/client/src/units/unit.ts index fd092a2e..71c348e7 100644 --- a/client/src/units/unit.ts +++ b/client/src/units/unit.ts @@ -383,6 +383,7 @@ export class Unit extends Marker { var unitAltitudeDiv = element.querySelector(".unit-altitude"); if (unitAltitudeDiv != null) { unitAltitudeDiv.innerHTML = String(Math.floor(this.getFlightData().altitude / 0.3048 / 1000)); + } const headingDeg = rad2deg( this.getFlightData().heading ); @@ -392,7 +393,10 @@ export class Unit extends Marker { el.setAttribute( "style", currentStyle + `transform:rotate(${headingDeg}deg);` ); }); - + var unitSpeedDiv = element.querySelector(".unit-speed"); + if (unitSpeedDiv != null) + unitSpeedDiv.innerHTML = String(Math.floor(this.getFlightData().speed * 1.94384 ) ); + } var pos = getMap().latLngToLayerPoint(this.getLatLng()).round(); this.setZIndexOffset(1000 + Math.floor(this.getFlightData().altitude) - pos.y); @@ -499,8 +503,8 @@ export class Aircraft extends AirUnit {
${data.baseData.unitName}
-
+
`); } diff --git a/client/src/units/unitdatatable.ts b/client/src/units/unitdatatable.ts new file mode 100644 index 00000000..4149cebb --- /dev/null +++ b/client/src/units/unitdatatable.ts @@ -0,0 +1,103 @@ +export class UnitDataTable { + + #element; + #tableId = "unit-data-table"; + + + constructor() { + + const table = document.getElementById( this.#tableId ); + + if ( table instanceof HTMLElement ) { + + this.#element = table; + + } else { + + return; + + } + + + } + + + getElement() { + return this.#element; + } + + + hide() { + this.getElement()?.closest( ".ol-dialog" )?.classList.add( "hide" ); + } + + + show() { + this.getElement()?.closest( ".ol-dialog" )?.classList.remove( "hide" ); + } + + + toggle() { + this.getElement()?.closest( ".ol-dialog" )?.classList.toggle( "hide" ); + } + + + update( units:object ) { + + const unitsArray = Object.values( units ).sort( ( a, b ) => { + + const aVal = a.baseData.unitName.toLowerCase(); + const bVal = b.baseData.unitName.toLowerCase(); + + if ( aVal > bVal ) { + return 1; + } else if ( bVal > aVal ) { + return -1; + } else { + return 0; + } + + }); + + + function addRow( parentEl:HTMLElement, columns:string[] ) { + + const rowDiv = document.createElement( "div" ); + + for ( const item of columns ) { + + const div = document.createElement( "div" ); + div.innerText = item; + rowDiv.appendChild( div ); + + } + + parentEl.appendChild( rowDiv ); + + } + + + const el = this.getElement(); + + if ( el ) { + + el.innerHTML = ""; + + addRow( el, [ "Callsign", "Name", "Category", "AI/Human" ] ) + + for ( const unit of unitsArray ) { + + const dataset = [ unit.baseData.unitName, unit.baseData.name, unit.baseData.category, ( unit.baseData.AI ) ? "AI" : "Human" ]; + + if ( this.getElement() ) { + + } + addRow( el, dataset ); + + } + + } + + } + +} \ No newline at end of file diff --git a/client/tsconfig.json b/client/tsconfig.json index 74c81cdf..d77f7eb3 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -9,7 +9,7 @@ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ diff --git a/client/views/index.ejs b/client/views/index.ejs index 3fbfbf5d..2a0a91ff 100644 --- a/client/views/index.ejs +++ b/client/views/index.ejs @@ -32,6 +32,7 @@ <%- include('navbar.ejs') %> <%- include('connectionstatuspanel.ejs') %> <%- include('dialogs.ejs') %> + <%- include('unitdatatable.ejs') %> <% /* %> <%- include('log.ejs') %> diff --git a/client/views/mouseinfopanel.ejs b/client/views/mouseinfopanel.ejs index 935e1694..ecf62d24 100644 --- a/client/views/mouseinfopanel.ejs +++ b/client/views/mouseinfopanel.ejs @@ -4,23 +4,25 @@
+
+
-
+
-
+
-
+
-
+
diff --git a/client/views/unitdatatable.ejs b/client/views/unitdatatable.ejs new file mode 100644 index 00000000..fb89a424 --- /dev/null +++ b/client/views/unitdatatable.ejs @@ -0,0 +1,13 @@ +
+ +
+ +
+

Unit list

+
+ +
+ +
+ +
\ No newline at end of file