From a23bdd4b330acd745b87f9e4972ff5aec0cb8f4b Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Mon, 1 May 2023 21:51:46 +0200 Subject: [PATCH] Multiple map panning fixes and improvements --- client/debug.bat | 2 +- client/public/stylesheets/units.css | 372 +++++++++++++------------ client/src/index.ts | 34 ++- client/src/map/boxselect.ts | 2 +- client/src/map/map.ts | 206 ++++++++------ client/src/units/unit.ts | 4 +- client/views/connectionstatuspanel.ejs | 2 +- client/views/contextmenus.ejs | 6 +- client/views/dialogs.ejs | 6 +- client/views/mouseinfopanel.ejs | 2 +- client/views/navbar.ejs | 2 +- client/views/popups.ejs | 2 +- client/views/unitcontrolpanel.ejs | 2 +- client/views/unitdatatable.ejs | 2 +- client/views/unitinfopanel.ejs | 2 +- 15 files changed, 357 insertions(+), 289 deletions(-) diff --git a/client/debug.bat b/client/debug.bat index be565780..f57b8be0 100644 --- a/client/debug.bat +++ b/client/debug.bat @@ -1,2 +1,2 @@ start cmd /k "npm run start" -start cmd /k "watchify .\src\index.ts --debug -p [ tsify --noImplicitAny ] -o .\public\javascripts\bundle.js" +start cmd /k "watchify .\src\index.ts --debug -o .\public\javascripts\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ] diff --git a/client/public/stylesheets/units.css b/client/public/stylesheets/units.css index ddd1bd77..1822effd 100644 --- a/client/public/stylesheets/units.css +++ b/client/public/stylesheets/units.css @@ -1,46 +1,48 @@ :root { - /* Generic marker settings */ - --unit-centre-x: calc( var( --unit-width ) / 2 ); - --unit-centre-y: calc( var( --unit-height ) / 2 ); - - --unit-hotgroup-height: 10px; - --unit-hotgroup-width: var( --unit-hotgroup-height ); - - - /* Air units' marker settings */ - --unit-aircraft-label-x: calc( var( --unit-centre-x ) - ( var( --unit-aircraft-width ) / 2 ) + ( var( --unit-stroke-width ) / 2 ) ); - --unit-aircraft-label-y: calc( var( --unit-centre-y ) - ( var( --unit-aircraft-height ) / 2 ) + ( var( --unit-stroke-width ) / 2 ) ); + /* Generic marker settings */ + --unit-centre-x: calc(var(--unit-width) / 2); + --unit-centre-y: calc(var(--unit-height) / 2); + + --unit-hotgroup-height: 10px; + --unit-hotgroup-width: var(--unit-hotgroup-height); + + + /* Air units' marker settings */ + --unit-aircraft-label-x: calc(var(--unit-centre-x) - (var(--unit-aircraft-width) / 2) + (var(--unit-stroke-width) / 2)); + --unit-aircraft-label-y: calc(var(--unit-centre-y) - (var(--unit-aircraft-height) / 2) + (var(--unit-stroke-width) / 2)); } [data-object|="unit"] { align-items: center; - cursor:pointer; - display:flex; + cursor: pointer; + display: flex; justify-content: center; - position:relative; + position: relative; + height: 100%; + width: 100%; } [data-object|="unit"] .unit-selected-spotlight { - background-color: var( --unit-spotlight-fill ); + background-color: var(--unit-spotlight-fill); border-radius: 50%; - display:none; - padding: var( --unit-spotlight-radius ); + display: none; + padding: var(--unit-spotlight-radius); position: absolute; - z-index:1; + z-index: 1; } [data-object|="unit"] .unit-vvi { align-self: center; - background:var( --secondary-gunmetal-grey ); - display:flex; + background: var(--secondary-gunmetal-grey); + display: flex; justify-self: center; transform-origin: bottom; - translate:0 -50%; - padding-bottom: calc( ( var( --unit-aircraft-width ) / 2 ) + var( --unit-stroke-width ) ); - position:absolute; - width: var( --unit-aircraft-vvi-width ); + translate: 0 -50%; + padding-bottom: calc((var(--unit-aircraft-width) / 2) + var(--unit-stroke-width)); + position: absolute; + width: var(--unit-aircraft-vvi-width); z-index: 3; } @@ -48,32 +50,32 @@ [data-object|="unit"] .unit-hotgroup { align-content: center; background-color: black; - border-radius: var( --border-radius-xs ); - display:none; - height: var( --unit-hotgroup-height ); + border-radius: var(--border-radius-xs); + display: none; + height: var(--unit-hotgroup-height); justify-content: center; - position:absolute; - transform: rotate( -45deg ); - translate:0 -275%; - width: var( --unit-hotgroup-width ); + position: absolute; + transform: rotate(-45deg); + translate: 0 -275%; + width: var(--unit-hotgroup-width); z-index: 5; } [data-object|="unit"] .unit-hotgroup-id { background-color: transparent; - color:white; + color: white; font-size: 9px; font-weight: bolder; - transform:rotate( 45deg ); + transform: rotate(45deg); } [data-object|="unit"] .unit-marker-border { - border-radius: var( --border-radius-sm ); - display:none; - height: calc( var( --unit-aircraft-height ) + ( var( --unit-label-border-width ) * 2 ) ); - position:absolute; - width: calc( var( --unit-aircraft-width ) + ( var( --unit-label-border-width ) * 2 ) ); - z-index:2; + border-radius: var(--border-radius-sm); + display: none; + height: calc(var(--unit-aircraft-height) + (var(--unit-label-border-width) * 2)); + position: absolute; + width: calc(var(--unit-aircraft-width) + (var(--unit-label-border-width) * 2)); + z-index: 2; } @@ -85,9 +87,9 @@ background-color: transparent; background-repeat: no-repeat; background-size: cover; - position:absolute; + position: absolute; transform-origin: center; - z-index:3; + z-index: 3; } @@ -95,43 +97,43 @@ /* Air */ [data-object|="unit-aircraft"] .unit-marker { - background-image: var( --unit-aircraft-marker-neutral-url ); - height: var( --unit-aircraft-marker-height ); - width: var( --unit-aircraft-marker-width ); + background-image: var(--unit-aircraft-marker-neutral-url); + height: var(--unit-aircraft-marker-height); + width: var(--unit-aircraft-marker-width); } [data-object|="unit-aircraft"]:hover .unit-marker { - background-image: var( --unit-aircraft-marker-neutral-hover-url ); + background-image: var(--unit-aircraft-marker-neutral-hover-url); } [data-object|="unit-aircraft"][data-is-selected] .unit-marker { - background-image: var( --unit-aircraft-marker-neutral-selected-url ); + background-image: var(--unit-aircraft-marker-neutral-selected-url); } [data-object|="unit-aircraft"][data-coalition="blue"] .unit-marker { - background-image: var( --unit-aircraft-marker-blue-url ); + background-image: var(--unit-aircraft-marker-blue-url); } [data-object|="unit-aircraft"][data-coalition="blue"]:hover .unit-marker { - background-image: var( --unit-aircraft-marker-blue-hover-url ); + background-image: var(--unit-aircraft-marker-blue-hover-url); } [data-object|="unit-aircraft"][data-coalition="blue"][data-is-selected] .unit-marker { - background-image: var( --unit-aircraft-marker-blue-selected-url ); + background-image: var(--unit-aircraft-marker-blue-selected-url); } [data-object|="unit-aircraft"][data-coalition="red"] .unit-marker { - background-image: var( --unit-aircraft-marker-red-url ); + background-image: var(--unit-aircraft-marker-red-url); } [data-object|="unit-aircraft"][data-coalition="red"]:hover .unit-marker { - background-image: var( --unit-aircraft-marker-red-hover-url ); + background-image: var(--unit-aircraft-marker-red-hover-url); } [data-object|="unit-aircraft"][data-coalition="red"][data-is-selected] .unit-marker { - background-image: var( --unit-aircraft-marker-red-selected-url ); + background-image: var(--unit-aircraft-marker-red-selected-url); } @@ -140,194 +142,195 @@ /* Ground vehicles (not SAMs) */ [data-object|="unit-groundunit"] .unit-marker { - background-image: var( --unit-groundunit-marker-neutral-url ); - height: var( --unit-groundunit-marker-height ); - width: var( --unit-groundunit-marker-width ); + background-image: var(--unit-groundunit-marker-neutral-url); + height: var(--unit-groundunit-marker-height); + width: var(--unit-groundunit-marker-width); } [data-object|="unit-groundunit"]:hover .unit-marker { - background-image: var( --unit-groundunit-marker-neutral-hover-url ); + background-image: var(--unit-groundunit-marker-neutral-hover-url); } [data-object|="unit-groundunit"][data-is-selected] .unit-marker { - background-image: var( --unit-groundunit-marker-neutral-selected-url ); + background-image: var(--unit-groundunit-marker-neutral-selected-url); } [data-object|="unit-groundunit"][data-coalition="blue"] .unit-marker { - background-image: var( --unit-groundunit-marker-blue-url ); + background-image: var(--unit-groundunit-marker-blue-url); } [data-object|="unit-groundunit"][data-coalition="blue"]:hover .unit-marker { - background-image: var( --unit-groundunit-marker-blue-hover-url ); + background-image: var(--unit-groundunit-marker-blue-hover-url); } [data-object|="unit-groundunit"][data-coalition="blue"][data-is-selected] .unit-marker { - background-image: var( --unit-groundunit-marker-blue-selected-url ); + background-image: var(--unit-groundunit-marker-blue-selected-url); } [data-object|="unit-groundunit"][data-coalition="red"] .unit-marker { - background-image: var( --unit-groundunit-marker-red-url ); + background-image: var(--unit-groundunit-marker-red-url); } [data-object|="unit-groundunit"][data-coalition="red"]:hover .unit-marker { - background-image: var( --unit-groundunit-marker-red-hover-url ); + background-image: var(--unit-groundunit-marker-red-hover-url); } [data-object|="unit-groundunit"][data-coalition="red"][data-is-selected] .unit-marker { - background-image: var( --unit-groundunit-marker-red-selected-url ); + background-image: var(--unit-groundunit-marker-red-selected-url); } /* SAMs */ [data-object|="unit-sam"] .unit-selected-spotlight { - translate:0 2px; + translate: 0 2px; } [data-object|="unit-sam"] .unit-marker { - background-image: var( --unit-sam-marker-neutral-url ); - height: var( --unit-sam-marker-height ); - width: var( --unit-sam-marker-width ); + background-image: var(--unit-sam-marker-neutral-url); + height: var(--unit-sam-marker-height); + width: var(--unit-sam-marker-width); } [data-object|="unit-sam"]:hover .unit-marker { - background-image: var( --unit-sam-marker-neutral-hover-url ); + background-image: var(--unit-sam-marker-neutral-hover-url); } [data-object|="unit-sam"][data-is-selected] .unit-marker { - background-image: var( --unit-sam-marker-neutral-selected-url ); + background-image: var(--unit-sam-marker-neutral-selected-url); } [data-object|="unit-sam"][data-coalition="blue"] .unit-marker { - background-image: var( --unit-sam-marker-blue-url ); + background-image: var(--unit-sam-marker-blue-url); } [data-object|="unit-sam"][data-coalition="blue"]:hover .unit-marker { - background-image: var( --unit-sam-marker-blue-hover-url ); + background-image: var(--unit-sam-marker-blue-hover-url); } [data-object|="unit-sam"][data-coalition="blue"][data-is-selected] .unit-marker { - background-image: var( --unit-sam-marker-blue-selected-url ); + background-image: var(--unit-sam-marker-blue-selected-url); } [data-object|="unit-sam"][data-coalition="red"] .unit-marker { - background-image: var( --unit-sam-marker-red-url ); + background-image: var(--unit-sam-marker-red-url); } [data-object|="unit-sam"][data-coalition="red"]:hover .unit-marker { - background-image: var( --unit-sam-marker-red-hover-url ); + background-image: var(--unit-sam-marker-red-hover-url); } [data-object|="unit-sam"][data-coalition="red"][data-is-selected] .unit-marker { - background-image: var( --unit-sam-marker-red-selected-url ); + background-image: var(--unit-sam-marker-red-selected-url); } /* navyunit */ [data-object|="unit-navyunit"] .unit-selected-spotlight { - translate:0 -2px; + translate: 0 -2px; } [data-object|="unit-navyunit"] .unit-marker { - background-image: var( --unit-navyunit-marker-neutral-url ); - height: var( --unit-navyunit-marker-height ); - width: var( --unit-navyunit-marker-width ); + background-image: var(--unit-navyunit-marker-neutral-url); + height: var(--unit-navyunit-marker-height); + width: var(--unit-navyunit-marker-width); } [data-object|="unit-navyunit"]:hover .unit-marker { - background-image: var( --unit-navyunit-marker-neutral-hover-url ); + background-image: var(--unit-navyunit-marker-neutral-hover-url); } [data-object|="unit-navyunit"][data-is-selected] .unit-marker { - background-image: var( --unit-navyunit-marker-neutral-selected-url ); + background-image: var(--unit-navyunit-marker-neutral-selected-url); } [data-object|="unit-navyunit"][data-coalition="blue"] .unit-marker { - background-image: var( --unit-navyunit-marker-blue-url ); + background-image: var(--unit-navyunit-marker-blue-url); } [data-object|="unit-navyunit"][data-coalition="blue"]:hover .unit-marker { - background-image: var( --unit-navyunit-marker-blue-hover-url ); + background-image: var(--unit-navyunit-marker-blue-hover-url); } [data-object|="unit-navyunit"][data-coalition="blue"][data-is-selected] .unit-marker { - background-image: var( --unit-navyunit-marker-blue-selected-url ); + background-image: var(--unit-navyunit-marker-blue-selected-url); } [data-object|="unit-navyunit"][data-coalition="red"] .unit-marker { - background-image: var( --unit-navyunit-marker-red-url ); + background-image: var(--unit-navyunit-marker-red-url); } [data-object|="unit-navyunit"][data-coalition="red"]:hover .unit-marker { - background-image: var( --unit-navyunit-marker-red-hover-url ); + background-image: var(--unit-navyunit-marker-red-hover-url); } [data-object|="unit-navyunit"][data-coalition="red"][data-is-selected] .unit-marker { - background-image: var( --unit-navyunit-marker-red-selected-url ); + background-image: var(--unit-navyunit-marker-red-selected-url); } /* Building */ [data-object|="unit-building"] .unit-marker { - background-image: var( --unit-building-marker-neutral-url ); - height: var( --unit-building-marker-height ); - width: var( --unit-building-marker-width ); + background-image: var(--unit-building-marker-neutral-url); + height: var(--unit-building-marker-height); + width: var(--unit-building-marker-width); } [data-object|="unit-building"][data-coalition="blue"] .unit-marker { - background-image: var( --unit-building-marker-blue-url ); + background-image: var(--unit-building-marker-blue-url); } [data-object|="unit-building"][data-coalition="red"] .unit-marker { - background-image: var( --unit-building-marker-red-url ); + background-image: var(--unit-building-marker-red-url); } /* Weapons */ -[data-object|="unit-missile"], [data-object|="unit-bomb"] { +[data-object|="unit-missile"], +[data-object|="unit-bomb"] { cursor: default; } [data-object|="unit-missile"] .unit-marker { - background-image: var( --unit-missile-marker-neutral-url ); - height: var( --unit-missile-marker-height ); - width: var( --unit-missile-marker-width ); + background-image: var(--unit-missile-marker-neutral-url); + height: var(--unit-missile-marker-height); + width: var(--unit-missile-marker-width); } [data-object|="unit-missile"][data-coalition="blue"] .unit-marker { - background-image: var( --unit-missile-marker-blue-url ); + background-image: var(--unit-missile-marker-blue-url); } [data-object|="unit-missile"][data-coalition="red"] .unit-marker { - background-image: var( --unit-missile-marker-red-url ); + background-image: var(--unit-missile-marker-red-url); } [data-object|="unit-bomb"] .unit-marker { - background-image: var( --unit-bomb-marker-neutral-url ); - height: var( --unit-bomb-marker-height ); - width: var( --unit-bomb-marker-width ); + background-image: var(--unit-bomb-marker-neutral-url); + height: var(--unit-bomb-marker-height); + width: var(--unit-bomb-marker-width); } [data-object|="unit-bomb"][data-coalition="blue"] .unit-marker { - background-image: var( --unit-bomb-marker-blue-url ); + background-image: var(--unit-bomb-marker-blue-url); } [data-object|="unit-bomb"][data-coalition="red"] .unit-marker { - background-image: var( --unit-bomb-marker-red-url ); + background-image: var(--unit-bomb-marker-red-url); } @@ -336,12 +339,12 @@ ********************************************/ [data-object|="unit"] .unit-short-label { - color: var( --secondary-gunmetal-grey ); + color: var(--secondary-gunmetal-grey); font-size: var(--unit-font-size); font-weight: var(--unit-font-weight); line-height: normal; position: absolute; - z-index:10; + z-index: 10; } [data-object|="unit-groundunit"] .unit-short-label { @@ -349,81 +352,81 @@ } [data-object|="unit-sam"] .unit-short-label { - translate:0 50%; + translate: 0 50%; } [data-object|="unit-navyunit"] .unit-short-label { - translate:0 -50%; + translate: 0 -50%; } [data-object|="unit"] .unit-fuel { - background:white; - border: var( --unit-aircraft-fuel-border-width ) solid var( --secondary-dark-steel ); - border-radius: var( --border-radius-sm ); - display:none; - height: var( --unit-aircraft-fuel-height ); + background: white; + border: var(--unit-aircraft-fuel-border-width) solid var(--secondary-dark-steel); + border-radius: var(--border-radius-sm); + display: none; + height: var(--unit-aircraft-fuel-height); position: absolute; - translate:var( --unit-aircraft-fuel-x ) var( --unit-aircraft-fuel-y ); - width: var( --unit-aircraft-fuel-width ); + translate: var(--unit-aircraft-fuel-x) var(--unit-aircraft-fuel-y); + width: var(--unit-aircraft-fuel-width); z-index: 5; } [data-object|="unit"] .unit-fuel-level { - background-color: var( --secondary-light-grey ); - height:100%; - width:100%; + background-color: var(--secondary-light-grey); + height: 100%; + width: 100%; } [data-object|="unit"] .unit-ammo { - column-gap: var( --unit-aircraft-ammo-spacing ); - display:none; - height:fit-content; - position:absolute; - translate:var( --unit-aircraft-ammo-x ) var( --unit-aircraft-ammo-y ); - width:fit-content; + column-gap: var(--unit-aircraft-ammo-spacing); + display: none; + height: fit-content; + position: absolute; + translate: var(--unit-aircraft-ammo-x) var(--unit-aircraft-ammo-y); + width: fit-content; } -[data-object|="unit"] .unit-ammo > * { +[data-object|="unit"] .unit-ammo>* { background-color: white; - border: var( --unit-aircraft-ammo-border-width ) solid var( --secondary-dark-steel ); + border: var(--unit-aircraft-ammo-border-width) solid var(--secondary-dark-steel); border-radius: 50%; - padding: var( --unit-aircraft-ammo-radius ); + padding: var(--unit-aircraft-ammo-radius); } [data-object|="unit"] .unit-summary { pointer-events: none; column-gap: 6px; - color:white; - display:flex; + color: white; + display: flex; flex-wrap: wrap; - font-size:11px; + font-size: 11px; font-weight: bold; justify-content: right; line-height: 12px; - position:absolute; + position: absolute; row-gap: 1px; text-shadow: - -1px -1px 0 #000, + -1px -1px 0 #000, 1px -1px 0 #000, - -1px 1px 0 #000, - 1px 1px 0 #000; + -1px 1px 0 #000, + 1px 1px 0 #000; translate: -60px 0; - width:fit-content; - z-index:20; + width: fit-content; + z-index: 20; } [data-hide-labels] [data-object|="unit"] .unit-summary { - display:none; + display: none; } -[data-object|="unit"] .unit-summary > * { - padding:1px; +[data-object|="unit"] .unit-summary>* { + padding: 1px; } [data-object|="unit"] .unit-summary .unit-callsign { - color:white; + color: white; overflow: hidden; text-align: right; transform-origin: right; @@ -433,35 +436,35 @@ [data-object|="unit"] .unit-summary .unit-callsign:hover { direction: rtl; - overflow:visible; + overflow: visible; } [data-object|="unit"]:hover .unit-ammo, [data-object|="unit"]:hover .unit-fuel { - display:flex; + display: flex; } [data-object|="unit"][data-is-in-hotgroup] .unit-hotgroup, [data-object|="unit"][data-is-selected] .unit-ammo, [data-object|="unit"][data-is-selected] .unit-fuel, [data-object|="unit"][data-is-selected] .unit-selected-spotlight { - display:flex; + display: flex; } [data-object|="unit"][data-has-fox-1] .unit-ammo-fox-1, [data-object|="unit"][data-has-fox-2] .unit-ammo-fox-2, [data-object|="unit"][data-has-fox-3] .unit-ammo-fox-3, [data-object|="unit"][data-has-other-ammo] .unit-ammo-other { - background-color: var( --secondary-gunmetal-grey ); + background-color: var(--secondary-gunmetal-grey); } [data-object|="unit"][data-coalition="blue"][data-is-selected] .unit-short-label { - color: var( --secondary-blue-text ); + color: var(--secondary-blue-text); } [data-object|="unit"][data-coalition="blue"] .unit-fuel-level, @@ -469,16 +472,16 @@ [data-object|="unit"][data-coalition="blue"][data-has-fox-2] .unit-ammo-fox-2, [data-object|="unit"][data-coalition="blue"][data-has-fox-3] .unit-ammo-fox-3, [data-object|="unit"][data-coalition="blue"][data-has-other-ammo] .unit-ammo-other { - background-color: var( --primary-blue ); + background-color: var(--primary-blue); } [data-object|="unit"][data-coalition="blue"] .unit-vvi { - background-color: var( --secondary-blue-outline ); + background-color: var(--secondary-blue-outline); } [data-object|="unit"][data-coalition="red"][data-is-selected] .unit-short-label { - color: var( --secondary-red-text ); + color: var(--secondary-red-text); } [data-object|="unit"][data-coalition="red"] .unit-fuel-level, @@ -486,18 +489,18 @@ [data-object|="unit"][data-coalition="red"][data-has-fox-2] .unit-ammo-fox-2, [data-object|="unit"][data-coalition="red"][data-has-fox-3] .unit-ammo-fox-3, [data-object|="unit"][data-coalition="red"][data-has-other-ammo] .unit-ammo-other { - background-color: var( --primary-red ); + background-color: var(--primary-red); } [data-object|="unit"][data-coalition="blue"] .unit-vvi { - background-color: var( --secondary-red-outline ); + background-color: var(--secondary-red-outline); } @keyframes pulse { 50% { - opacity: 0; + opacity: 0; } } @@ -508,83 +511,82 @@ [data-object|="unit"] .unit-state { background-repeat: no-repeat; - position:absolute; - height:var( --unit-aircraft-state-height ); - width:var( --unit-aircraft-state-width ); + position: absolute; + height: var(--unit-aircraft-state-height); + width: var(--unit-aircraft-state-width); z-index: 10; } [data-object|="unit"][data-state="rtb"] .unit-state { - background-image: var( --unit-aircraft-state-rtb ); + background-image: var(--unit-aircraft-state-rtb); } [data-object|="unit"][data-state="land"] .unit-state { - background-image: var( --unit-aircraft-state-rtb ); + background-image: var(--unit-aircraft-state-rtb); } [data-object|="unit"][data-state="idle"] .unit-state { - background-image: var( --unit-aircraft-state-idle ); + background-image: var(--unit-aircraft-state-idle); } [data-object|="unit"][data-state="attack"] .unit-state { - background-image: var( --unit-aircraft-state-attack ); + background-image: var(--unit-aircraft-state-attack); } [data-object|="unit"][data-state="follow"] .unit-state { - background-image: var( --unit-aircraft-state-follow ); + background-image: var(--unit-aircraft-state-follow); } [data-object|="unit"][data-state="refuel"] .unit-state { - background-image: var( --unit-aircraft-state-refuel ); + background-image: var(--unit-aircraft-state-refuel); } [data-object|="unit"][data-state="human"] .unit-state { - background-image: var( --unit-aircraft-state-human ); + background-image: var(--unit-aircraft-state-human); } [data-object|="unit"][data-state="dcs"] .unit-state { - background-image: var( --unit-aircraft-state-dcs ); + background-image: var(--unit-aircraft-state-dcs); } /*** DEAD ***/ -[data-object|="unit-aircraft"][ data-is-dead ] { +[data-object|="unit-aircraft"][ data-is-dead] { cursor: default; } -[data-object|="unit-aircraft"][ data-is-dead ] .unit-marker { - background-image: var( --unit-aircraft-marker-neutral-dead-url ); +[data-object|="unit-aircraft"][ data-is-dead] .unit-marker { + background-image: var(--unit-aircraft-marker-neutral-dead-url); background-position: 50% 50%; background-size: auto 32px; } -[data-object|="unit-aircraft"][ data-is-dead ][data-coalition="blue"] .unit-marker { - background-image: var( --unit-aircraft-marker-blue-dead-url ); +[data-object|="unit-aircraft"][ data-is-dead][data-coalition="blue"] .unit-marker { + background-image: var(--unit-aircraft-marker-blue-dead-url); } -[data-object|="unit-aircraft"][ data-is-dead ][data-coalition="red"] .unit-marker { - background-image: var( --unit-aircraft-marker-red-dead-url ); +[data-object|="unit-aircraft"][ data-is-dead][data-coalition="red"] .unit-marker { + background-image: var(--unit-aircraft-marker-red-dead-url); } -[data-object|="unit-aircraft"][ data-is-dead ] .unit-selected-spotlight, -[data-object|="unit-aircraft"][ data-is-dead ] .unit-short-label, -[data-object|="unit-aircraft"][ data-is-dead ] .unit-vvi, -[data-object|="unit-aircraft"][ data-is-dead ] .unit-hotgroup, -[data-object|="unit-aircraft"][ data-is-dead ] .unit-hotgroup-id, -[data-object|="unit-aircraft"][ data-is-dead ] .unit-state, -[data-object|="unit-aircraft"][ data-is-dead ] .unit-fuel, -[data-object|="unit-aircraft"][ data-is-dead ] .unit-ammo, -[data-object|="unit-aircraft"][ data-is-dead ]:hover .unit-fuel, -[data-object|="unit-aircraft"][ data-is-dead ]:hover .unit-ammo { - display:none !important; +[data-object|="unit-aircraft"][ data-is-dead] .unit-selected-spotlight, +[data-object|="unit-aircraft"][ data-is-dead] .unit-short-label, +[data-object|="unit-aircraft"][ data-is-dead] .unit-vvi, +[data-object|="unit-aircraft"][ data-is-dead] .unit-hotgroup, +[data-object|="unit-aircraft"][ data-is-dead] .unit-hotgroup-id, +[data-object|="unit-aircraft"][ data-is-dead] .unit-state, +[data-object|="unit-aircraft"][ data-is-dead] .unit-fuel, +[data-object|="unit-aircraft"][ data-is-dead] .unit-ammo, +[data-object|="unit-aircraft"][ data-is-dead]:hover .unit-fuel, +[data-object|="unit-aircraft"][ data-is-dead]:hover .unit-ammo { + display: none !important; } -[data-object|="unit-aircraft"][ data-is-dead ] .unit-summary > * { - display:none; -} - -[data-object|="unit-aircraft"][ data-is-dead ] .unit-summary .unit-callsign { - display:block; +[data-object|="unit-aircraft"][ data-is-dead] .unit-summary>* { + display: none; } +[data-object|="unit-aircraft"][ data-is-dead] .unit-summary .unit-callsign { + display: block; +} \ No newline at end of file diff --git a/client/src/index.ts b/client/src/index.ts index 2c817671..d5f41186 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -192,7 +192,7 @@ function setupEvents() { case "KeyL": document.body.toggleAttribute("data-hide-labels"); break; - case "KeyD": + case "KeyT": toggleDemoEnabled(); break; case "Quote": @@ -201,6 +201,37 @@ function setupEvents() { case "Space": setPaused(!getPaused()); break; + case "KeyW": + case "KeyA": + case "KeyS": + case "KeyD": + case "ArrowLeft": + case "ArrowRight": + case "ArrowUp": + case "ArrowDown": + getMap().handleMapPanning(ev); + break; + } + }); + + /* Keydown events */ + document.addEventListener("keydown", ev => { + + if ( keyEventWasInInput( ev ) ) { + return; + } + + switch (ev.code) { + case "KeyW": + case "KeyA": + case "KeyS": + case "KeyD": + case "ArrowLeft": + case "ArrowRight": + case "ArrowUp": + case "ArrowDown": + getMap().handleMapPanning(ev); + break; } }); @@ -231,7 +262,6 @@ function setupEvents() { el.classList.toggle( "hide" ); }) }); - } export function getMap() { diff --git a/client/src/map/boxselect.ts b/client/src/map/boxselect.ts index 421509ef..6161fa88 100644 --- a/client/src/map/boxselect.ts +++ b/client/src/map/boxselect.ts @@ -45,7 +45,7 @@ export var BoxSelect = Handler.extend({ }, _onMouseDown: function (e: any) { - if (((e.which !== 1) && (e.button !== 0))) { return false; } + if ((e.which !== 1 && e.button !== 0) || !e.shiftKey) { return false; } // Clear the deferred resetState if it hasn't executed yet, otherwise it // will interrupt the interaction and orphan a box element in the container. diff --git a/client/src/map/map.ts b/client/src/map/map.ts index be0c7031..46f7b0ae 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -19,8 +19,7 @@ export const MOVE_UNIT = "MOVE_UNIT"; L.Map.addInitHook('addHandler', 'boxSelect', BoxSelect); export class ClickableMiniMap extends MiniMap { - constructor(layer: L.TileLayer | L.LayerGroup, options?: MiniMapOptions) - { + constructor(layer: L.TileLayer | L.LayerGroup, options?: MiniMapOptions) { super(layer, options); } @@ -34,7 +33,11 @@ export class Map extends L.Map { #state: string; #layer: L.TileLayer | null = null; #preventLeftClick: boolean = false; - #leftClickTimer: any = 0; + #leftClickTimer: number = 0; + #deafultPanDelta: number = 100; + #panInterval: number | null = null; + #panDeltaX: number; + #panDeltaY: number; #lastMousePosition: L.Point = new L.Point(0, 0); #centerUnit: Unit | null = null; #miniMap: ClickableMiniMap | null = null; @@ -49,7 +52,7 @@ export class Map extends L.Map { constructor(ID: string) { /* Init the leaflet map */ //@ts-ignore - super(ID, { doubleClickZoom: false, zoomControl: false, boxZoom: false, boxSelect: true, zoomAnimation: true, maxBoundsViscosity: 1.0, minZoom: 7 }); + super(ID, { doubleClickZoom: false, zoomControl: false, boxZoom: false, boxSelect: true, zoomAnimation: true, maxBoundsViscosity: 1.0, minZoom: 7, keyboard: true, keyboardPanDelta: 0 }); this.setView([37.23, -115.8], 10); this.setLayer("ArcGIS Satellite"); @@ -57,59 +60,59 @@ export class Map extends L.Map { /* Minimap */ /* Draw the limits of the maps in the minimap*/ var latlngs = [[ // NTTR - new L.LatLng(39.7982463, -119.985425 ), - new L.LatLng(34.4037128, -119.7806729), - new L.LatLng(34.3483316, -112.4529351), - new L.LatLng(39.7372411, -112.1130805), - new L.LatLng(39.7982463, -119.985425 ) - ], - [ // Syria - new L.LatLng(37.3630556, 29.2686111), - new L.LatLng(31.8472222, 29.8975), - new L.LatLng(32.1358333, 42.1502778), - new L.LatLng(37.7177778, 42.3716667), - new L.LatLng(37.3630556, 29.2686111) - ], - [ // Caucasus - new L.LatLng(39.6170191, 27.634935), - new L.LatLng(38.8735863, 47.1423108), - new L.LatLng(47.3907982, 49.3101946), - new L.LatLng(48.3955879, 26.7753625), - new L.LatLng(39.6170191, 27.634935) - ], - [ // Persian Gulf - new L.LatLng(32.9355285, 46.5623682), - new L.LatLng(21.729393, 47.572675), - new L.LatLng(21.8501348, 63.9734737), - new L.LatLng(33.131584, 64.7313594), - new L.LatLng(32.9355285, 46.5623682) - ], - [ // Marianas - new L.LatLng(22.09, 135.0572222), - new L.LatLng(10.5777778, 135.7477778), - new L.LatLng(10.7725, 149.3918333), - new L.LatLng(22.5127778, 149.5427778), - new L.LatLng(22.09, 135.0572222) - ] - ]; + new L.LatLng(39.7982463, -119.985425), + new L.LatLng(34.4037128, -119.7806729), + new L.LatLng(34.3483316, -112.4529351), + new L.LatLng(39.7372411, -112.1130805), + new L.LatLng(39.7982463, -119.985425) + ], + [ // Syria + new L.LatLng(37.3630556, 29.2686111), + new L.LatLng(31.8472222, 29.8975), + new L.LatLng(32.1358333, 42.1502778), + new L.LatLng(37.7177778, 42.3716667), + new L.LatLng(37.3630556, 29.2686111) + ], + [ // Caucasus + new L.LatLng(39.6170191, 27.634935), + new L.LatLng(38.8735863, 47.1423108), + new L.LatLng(47.3907982, 49.3101946), + new L.LatLng(48.3955879, 26.7753625), + new L.LatLng(39.6170191, 27.634935) + ], + [ // Persian Gulf + new L.LatLng(32.9355285, 46.5623682), + new L.LatLng(21.729393, 47.572675), + new L.LatLng(21.8501348, 63.9734737), + new L.LatLng(33.131584, 64.7313594), + new L.LatLng(32.9355285, 46.5623682) + ], + [ // Marianas + new L.LatLng(22.09, 135.0572222), + new L.LatLng(10.5777778, 135.7477778), + new L.LatLng(10.7725, 149.3918333), + new L.LatLng(22.5127778, 149.5427778), + new L.LatLng(22.09, 135.0572222) + ] + ]; var minimapLayer = new L.TileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { minZoom: 0, maxZoom: 13 }); this.#miniMapLayerGroup = new L.LayerGroup([minimapLayer]); - var miniMapPolyline = new L.Polyline(latlngs, {color: '#202831'}); + var miniMapPolyline = new L.Polyline(latlngs, { color: '#202831' }); miniMapPolyline.addTo(this.#miniMapLayerGroup); - + /* Scale */ //@ts-ignore TODO more hacking because the module is provided as a pure javascript module only - L.control.scalenautic({position: "topright", maxWidth: 300, nautic: true, metric: true, imperial: false}).addTo(this); + L.control.scalenautic({ position: "topright", maxWidth: 300, nautic: true, metric: true, imperial: false }).addTo(this); /* Init the state machine */ this.#state = IDLE; /* Register event handles */ this.on("click", (e: any) => this.#onClick(e)); - this.on("dblclick", (e: any) => this.#onDoubleClick(e)); - this.on("zoomstart", (e: any) => this.#onZoom(e)); - this.on("drag", (e: any) => this.centerOnUnit(null)); + this.on("dblclick", (e: any) => this.#onDoubleClick(e)); + this.on("zoomstart", (e: any) => this.#onZoom(e)); + this.on("drag", (e: any) => this.centerOnUnit(null)); this.on("contextmenu", (e: any) => this.#onContextMenu(e)); this.on('selectionend', (e: any) => this.#onSelectionEnd(e)); this.on('mousedown', (e: any) => this.#onMouseDown(e)); @@ -121,7 +124,7 @@ export class Map extends L.Map { document.body.toggleAttribute("data-hide-" + ev.detail.coalition); Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); }); - + document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => { document.body.toggleAttribute("data-hide-" + ev.detail.category); Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); @@ -131,8 +134,15 @@ export class Map extends L.Map { if (this.#centerUnit != null && ev.detail == this.#centerUnit) this.#panToUnit(this.#centerUnit); }); - + this.#mapSourceDropdown = new Dropdown("map-type", (layerName: string) => this.setLayer(layerName), this.getLayers()) + + this.#panDeltaX = 0; + this.#panDeltaY = 0; + + this.#panInterval = window.setInterval(() => { + this.panBy(new L.Point(this.#panDeltaX, this.#panDeltaY)); + }, 20); } setLayer(layerName: string) { @@ -187,10 +197,10 @@ export class Map extends L.Map { setState(state: string) { this.#state = state; if (this.#state === IDLE) { - L.DomUtil.removeClass(this.getContainer(),'crosshair-cursor-enabled'); + L.DomUtil.removeClass(this.getContainer(), 'crosshair-cursor-enabled'); } else if (this.#state === MOVE_UNIT) { - L.DomUtil.addClass(this.getContainer(),'crosshair-cursor-enabled'); + L.DomUtil.addClass(this.getContainer(), 'crosshair-cursor-enabled'); } document.dispatchEvent(new CustomEvent("mapStateChanged")); } @@ -200,8 +210,7 @@ export class Map extends L.Map { } /* Context Menus */ - hideAllContextMenus() - { + hideAllContextMenus() { this.hideMapContextMenu(); this.hideUnitContextMenu(); this.hideAirbaseContextMenu(); @@ -220,7 +229,7 @@ export class Map extends L.Map { document.dispatchEvent(new CustomEvent("mapContextMenu")); } - getMapContextMenu(){ + getMapContextMenu() { return this.#mapContextMenu; } @@ -231,7 +240,7 @@ export class Map extends L.Map { this.#unitContextMenu.show(x, y, e.latlng); } - getUnitContextMenu(){ + getUnitContextMenu() { return this.#unitContextMenu; } @@ -247,7 +256,7 @@ export class Map extends L.Map { this.#airbaseContextMenu.setAirbase(airbase); } - getAirbaseContextMenu(){ + getAirbaseContextMenu() { return this.#airbaseContextMenu; } @@ -270,8 +279,7 @@ export class Map extends L.Map { } centerOnUnit(ID: number | null) { - if (ID != null) - { + if (ID != null) { this.options.scrollWheelZoom = 'center'; this.#centerUnit = getUnitsManager().getUnitByID(ID); } @@ -289,16 +297,14 @@ export class Map extends L.Map { else if (theatre == "MarianaIslands") bounds = new L.LatLngBounds([10.5777778, 135.7477778], [22.5127778, 149.5427778]); else if (theatre == "Nevada") - bounds = new L.LatLngBounds([34.4037128, -119.7806729], [39.7372411, -112.1130805]) + bounds = new L.LatLngBounds([34.4037128, -119.7806729], [39.7372411, -112.1130805]) else if (theatre == "PersianGulf") - bounds = new L.LatLngBounds([21.729393, 47.572675], [33.131584, 64.7313594]) - else if (theatre == "Falklands") - { + bounds = new L.LatLngBounds([21.729393, 47.572675], [33.131584, 64.7313594]) + else if (theatre == "Falklands") { // TODO } - else if (theatre == "Caucasus") - { - bounds = new L.LatLngBounds([39.6170191, 27.634935], [47.3907982, 49.3101946]) + else if (theatre == "Caucasus") { + bounds = new L.LatLngBounds([39.6170191, 27.634935], [47.3907982, 49.3101946]) miniMapZoom = 4; } @@ -309,25 +315,65 @@ export class Map extends L.Map { this.#miniMap.remove(); //@ts-ignore // Needed because some of the inputs are wrong in the original module interface - this.#miniMap = new ClickableMiniMap(this.#miniMapLayerGroup, {position: "topright", width: 192*1.5, height: 108*1.5, zoomLevelFixed: miniMapZoom, centerFixed: bounds.getCenter()}).addTo(this); + this.#miniMap = new ClickableMiniMap(this.#miniMapLayerGroup, { position: "topright", width: 192 * 1.5, height: 108 * 1.5, zoomLevelFixed: miniMapZoom, centerFixed: bounds.getCenter() }).addTo(this); this.#miniMap.disableInteractivity(); this.#miniMap.getMap().on("click", (e: any) => { if (this.#miniMap) this.setView(e.latlng); }) - + } getMiniMapLayerGroup() { return this.#miniMapLayerGroup; } + handleMapPanning(e: any) { + if (e.type === "keyup"){ + switch (e.code) { + case "KeyA": + case "KeyD": + case "ArrowLeft": + case "ArrowRight": + this.#panDeltaX = 0; + break; + case "KeyW": + case "KeyS": + case "ArrowUp": + case "ArrowDown": + this.#panDeltaY = 0 + break; + } + } + else { + switch (e.code) + { + case 'KeyD': + case 'ArrowRight': + this.#panDeltaX = this.#deafultPanDelta; + break; + case 'KeyA': + case 'ArrowLeft': + this.#panDeltaX = -this.#deafultPanDelta; + break; + case 'KeyW': + case 'ArrowUp': + this.#panDeltaY = -this.#deafultPanDelta; + break; + case 'KeyS': + case 'ArrowDown': + this.#panDeltaY = this.#deafultPanDelta; + break; + } + } + } + /* Event handlers */ #onClick(e: any) { if (!this.#preventLeftClick) { this.hideAllContextMenus(); if (this.#state === IDLE) { - + } else if (this.#state === MOVE_UNIT) { this.setState(IDLE); @@ -337,7 +383,7 @@ export class Map extends L.Map { } #onDoubleClick(e: any) { - + } #onContextMenu(e: any) { @@ -355,44 +401,34 @@ export class Map extends L.Map { } } - #onSelectionEnd(e: any) - { + #onSelectionEnd(e: any) { clearTimeout(this.#leftClickTimer); this.#preventLeftClick = true; this.#leftClickTimer = window.setTimeout(() => { - this.#preventLeftClick = false; + this.#preventLeftClick = false; }, 200); getUnitsManager().selectFromBounds(e.selectionBounds); } - #onMouseDown(e: any) - { + #onMouseDown(e: any) { this.hideAllContextMenus(); - if ((e.originalEvent.which == 1) && (e.originalEvent.button == 0)) - this.dragging.disable(); } - #onMouseUp(e: any) - { - if ((e.originalEvent.which == 1) && (e.originalEvent.button == 0)) - this.dragging.enable(); + #onMouseUp(e: any) { } - #onMouseMove(e: any) - { + #onMouseMove(e: any) { this.#lastMousePosition.x = e.originalEvent.x; this.#lastMousePosition.y = e.originalEvent.y; } - #onZoom(e: any) - { + #onZoom(e: any) { if (this.#centerUnit != null) this.#panToUnit(this.#centerUnit); } - #panToUnit(unit: Unit) - { + #panToUnit(unit: Unit) { var unitPosition = new L.LatLng(unit.getFlightData().latitude, unit.getFlightData().longitude); - this.setView(unitPosition, this.getZoom(), {animate: false}); + this.setView(unitPosition, this.getZoom(), { animate: false }); } } diff --git a/client/src/units/unit.ts b/client/src/units/unit.ts index 07c0c0e6..d3ee4338 100644 --- a/client/src/units/unit.ts +++ b/client/src/units/unit.ts @@ -89,7 +89,7 @@ export class Unit extends Marker { } constructor(ID: number, data: UpdateData) { - super(new LatLng(0, 0), { riseOnHover: true }); + super(new LatLng(0, 0), { riseOnHover: true, keyboard: false }); this.ID = ID; @@ -121,7 +121,7 @@ export class Unit extends Marker { var icon = new DivIcon({ html: this.getMarkerHTML(), className: 'leaflet-unit-marker', - iconAnchor: [25, 0], + iconAnchor: [25, 25], iconSize: [50, 50], }); this.setIcon(icon); diff --git a/client/views/connectionstatuspanel.ejs b/client/views/connectionstatuspanel.ejs index b0c7df1b..ac92da78 100644 --- a/client/views/connectionstatuspanel.ejs +++ b/client/views/connectionstatuspanel.ejs @@ -1,4 +1,4 @@ -
+
diff --git a/client/views/contextmenus.ejs b/client/views/contextmenus.ejs index b386ec9a..884642a9 100644 --- a/client/views/contextmenus.ejs +++ b/client/views/contextmenus.ejs @@ -1,4 +1,4 @@ -
+
-
+
-
+

diff --git a/client/views/dialogs.ejs b/client/views/dialogs.ejs index 1822808d..042c05be 100644 --- a/client/views/dialogs.ejs +++ b/client/views/dialogs.ejs @@ -1,4 +1,4 @@ -
+
@@ -17,7 +17,7 @@
-
+
@@ -141,7 +141,7 @@
-
+
diff --git a/client/views/mouseinfopanel.ejs b/client/views/mouseinfopanel.ejs index 932e4e01..5127e4a4 100644 --- a/client/views/mouseinfopanel.ejs +++ b/client/views/mouseinfopanel.ejs @@ -1,4 +1,4 @@ -
+
diff --git a/client/views/navbar.ejs b/client/views/navbar.ejs index aad54404..2ddf7c8d 100644 --- a/client/views/navbar.ejs +++ b/client/views/navbar.ejs @@ -1,4 +1,4 @@ -