Added switch toggle

This commit is contained in:
Pax1601 2023-05-27 10:06:34 +02:00
parent 9586910f03
commit 45bb49cfe1
18 changed files with 449 additions and 265 deletions

View File

@ -51,7 +51,7 @@
left: 10px;
position: absolute;
top: 80px;
width: 240px;
width: 320px;
z-index: 1000;
}

View File

@ -50,6 +50,7 @@ button {
cursor: pointer;
font-weight: var(--font-weight-bolder);
padding: 6px;
column-gap: 5px;
}
button:hover {
@ -61,6 +62,13 @@ button[disabled="disabled"] {
cursor: not-allowed;
}
button>svg:first-child,
button>img:first-child {
position: relative;
aspect-ratio: initial;
height: 100%;
}
form {
margin: 0;
padding: 0;
@ -121,10 +129,10 @@ form>div {
}
.ol-panel hr {
background-color: var(--secondary-light-grey);
background-color: var(--secondary-transparent-white);
border: none;
height: 1px;
margin: 20px 0;
margin: 10px 0;
width: 100%;
}
@ -356,6 +364,12 @@ h4 {
button.ol-button-warning {
border: 1px solid var(--primary-red);
color: var(--primary-red);
font-weight: bold;
}
button.ol-button-warning>svg:first-child {
stroke: var(--primary-red);
fill: var(--primary-red);
}
nav.ol-panel {
@ -482,16 +496,16 @@ nav.ol-panel> :last-child {
flex-direction: column;
}
.slider-container {
.ol-slider-container {
width: 100%;
}
.slider-container:not(:first-of-type) {
.ol-slider-container:not(:first-of-type) {
margin-top: 10px;
width: 100%;
}
.slider {
.ol-slider {
-webkit-appearance: none;
appearance: none;
background: #d3d3d3;
@ -505,34 +519,51 @@ nav.ol-panel> :last-child {
width: 100%;
}
.slider:hover {
.ol-slider:hover {
opacity: 1;
}
.slider::-webkit-slider-thumb {
.ol-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
background: gray;
background: var(--background-grey);
border-radius: 999px;
cursor: pointer;
height: 20px;
width: 20px;
height: 25px;
width: 25px;
}
.active .slider::-webkit-slider-thumb {
background: #5ca7ff;
.active .ol-slider::-webkit-slider-thumb {
background: radial-gradient(circle at center, var(--accent-light-blue), var(--accent-light-blue) 40%, color-mix(in srgb, var(--accent-light-blue), transparent 66%) 50%);
}
.slider::-moz-range-thumb {
background: gray;
.ol-slider::-moz-range-thumb {
-moz-appearance: none;
border: 0px solid transparent;
background: var(--background-grey);
border-radius: 999px;
cursor: pointer;
height: 20px;
width: 20px;
height: 25px;
width: 25px;
}
.active .slider::-moz-range-thumb {
background: #5ca7ff;
.active .ol-slider::-moz-range-thumb {
-moz-appearance: none;
background: radial-gradient(circle at center, var(--accent-light-blue), var(--accent-light-blue) 40%, color-mix(in srgb, var(--accent-light-blue), transparent 66%) 50%);
}
.ol-slider-min-max {
display: flex;
justify-content: space-between;
color: var(--secondary-light-grey);
}
.ol-slider-min-max::before {
content: attr(data-min-value);
}
.ol-slider-min-max::after {
content: attr(data-max-value);
}
.main-logo {
@ -848,12 +879,8 @@ dl.ol-data-grid {
row-gap: 4px;
}
dl.ol-data-grid dt {
width: 60%;
}
dl.ol-data-grid dd {
width: 40%;
width: fit-content;
}
dl.ol-data-grid dt.icon {
@ -1056,25 +1083,26 @@ input[type=number]::-webkit-outer-spin-button {
width: 24px;
}
.toggle {
.ol-switch {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-input {
.ol-switch-input {
display: none;
}
.toggle-fill {
.ol-switch-fill {
border-radius: 999px;
height: 20px;
position: relative;
transition: background-color 0.2s;
height: var(--height);
width: var(--width);
}
.toggle-fill::after {
.ol-switch-fill::after {
aspect-ratio : 1 / 1;
background-clip: content-box;
background-color: #ffffff;
@ -1082,7 +1110,29 @@ input[type=number]::-webkit-outer-spin-button {
box-sizing: border-box;
content: "";
height: 100%;
padding: 2px;
padding: 3px;
position: absolute;
transition: transform 0.2s;
top: 0px;
}
.ol-switch-fill::before {
align-items: center;
box-sizing: border-box;
color: white;
display: flex;
font-size: 11px;
height: 100%;
padding: 0px 7px;
position: absolute;
transition: transform 0.2s;
}
.ol-switch[data-value="false"]>.ol-switch-fill::before {
transform: translateX(calc(var(--width) - 100%));
}
.ol-switch[data-value="true"]>.ol-switch-fill::after {
transform: translateX(calc(var(--width) - var(--height)));
}

View File

@ -109,11 +109,11 @@
border-top-right-radius: var(--border-radius-sm);
}
#context-menu-switch .toggle-fill {
#context-menu-switch .ol-switch-fill {
width: 40;
}
[data-active-coalition="blue"].toggle-fill,
[data-active-coalition="blue"].ol-switch-fill,
[data-active-coalition="blue"].unit-spawn-button:hover,
[data-active-coalition="blue"].unit-spawn-button.is-open,
[data-active-coalition="blue"]#active-coalition-label,
@ -122,7 +122,7 @@
background-color: var(--primary-blue)
}
[data-active-coalition="red"].toggle-fill,
[data-active-coalition="red"].ol-switch-fill,
[data-active-coalition="red"].unit-spawn-button:hover,
[data-active-coalition="red"].unit-spawn-button.is-open,
[data-active-coalition="red"]#active-coalition-label,
@ -131,7 +131,7 @@
background-color: var(--primary-red)
}
[data-active-coalition="neutral"].toggle-fill,
[data-active-coalition="neutral"].ol-switch-fill,
[data-active-coalition="neutral"].unit-spawn-button:hover,
[data-active-coalition="neutral"].unit-spawn-button.is-open,
[data-active-coalition="neutral"]#active-coalition-label,
@ -158,15 +158,15 @@
cursor: default;
}
[data-active-coalition="blue"].toggle-fill::after {
[data-active-coalition="blue"].ol-switch-fill::after {
transform: translateX(0%);
}
[data-active-coalition="red"].toggle-fill::after {
[data-active-coalition="red"].ol-switch-fill::after {
transform: translateX(100%);
}
[data-active-coalition="neutral"].toggle-fill::after {
[data-active-coalition="neutral"].ol-switch-fill::after {
transform: translateX(50%);
}

View File

@ -2,6 +2,12 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
display: block !important;
}
#unit-control-panel {
display: flex;
flex-direction: column;
row-gap: 10px;
}
#unit-control-panel h3 {
margin-bottom: 8px;
}
@ -24,42 +30,27 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
font-size: 11px;
height: 32px;
margin-right: 5px;
padding: 8px 0;
position: relative;
width: calc(100% - 5px);
justify-content: space-between;
}
#unit-control-panel #selected-units-container button::before {
background-color: var(--primary-neutral);
#unit-control-panel #selected-units-container button::after {
border-radius: 999px;
content: attr(data-short-label);
color: var(--secondary-semitransparent-white);
content: attr(data-label);
font-size: 10px;
margin: 2px 4px;
max-width: 30px;
min-width: 20px;
overflow: hidden;
padding: 4px 6px;
text-overflow: ellipsis;
white-space: nowrap;
width: fit-content;
white-space: nowrap;
}
#unit-control-panel #selected-units-container button:hover::before {
background-color: black;
#unit-control-panel #selected-units-container button:hover::after {
max-width: 100%;
text-overflow: unset;
}
#unit-control-panel #selected-units-container button[data-coalition="blue"]::before {
background-color: var(--accent-light-blue);
}
#unit-control-panel #selected-units-container button[data-coalition="red"]::before {
background-color: var(--accent-light-red);
color: var(--secondary-red-outline)
}
#unit-control-panel #selected-units-container button::after {
#unit-control-panel #selected-units-container button::before {
border-radius: var(--border-radius-sm);
content: attr(data-callsign);
display: block;
@ -76,40 +67,10 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
margin-bottom: 8px;
}
#unit-control-panel #threat,
#unit-control-panel #roe,
#unit-control-panel #emissions-countermeasures {
margin-top: 12px;
}
#advanced-settings-dialog {
width: 400px;
}
#advanced-settings-dialog:not([data-show-settings]) #general-settings {
display: none;
}
#advanced-settings-dialog:not([data-show-tasking]) #tasking {
display: none;
}
#advanced-settings-dialog:not([data-show-tanker]) #tanker-checkbox {
display: none;
}
#advanced-settings-dialog:not([data-show-AWACS]) #AWACS-checkbox {
display: none;
}
#advanced-settings-dialog:not([data-show-TACAN]) #TACAN-options {
display: none;
}
#advanced-settings-dialog:not([data-show-radio]) #radio-options {
display: none;
}
#advanced-settings-dialog>.ol-dialog-content {
display: flex;
flex-direction: column;
@ -149,60 +110,155 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
width: 49%;
}
#altitude-type-switch>.toggle-fill {
background-color: var(--background-offwhite);
height: 15px;
width: 40px;
#flight-data .ol-slider {
margin: 20px 0px;
}
#altitude-type-switch>.toggle-fill::before {
display: flex;
position: absolute;
box-sizing: border-box;
align-items: center;
padding: 0px 5px;
color: var(--background-steel);
font-weight: bold;
font-size: 10px;
transition: transform 0.2s;
height: 15px;
.ol-slider-container dd {
column-gap: 5px;
}
#altitude-type-switch[data-altitude-type="agl"]>.toggle-fill::before {
#flight-data .ol-switch {
height: 20px;
width: 50px;
}
#flight-data .ol-switch-fill {
background-color: var(--accent-light-blue);
}
#flight-data .ol-switch-fill::after {
background-color: white;
}
#altitude-type-switch[data-value="true"]>.ol-switch-fill::before {
content: "AGL";
}
#altitude-type-switch[data-altitude-type="asl"]>.toggle-fill::before {
#altitude-type-switch[data-value="false"]>.ol-switch-fill::before {
content: "ASL";
transform: translateX(calc(40px - 28px));
}
#altitude-type-switch>.toggle-fill::after {
position: absolute;
display: block;
background-color: var(--background-steel);
width: 15px;
top: 0px;
#airspeed-type-switch[data-value="true"]>.ol-switch-fill::before {
content: "GS";
}
#altitude-type-switch[data-altitude-type="asl"]>.toggle-fill::after {
transform: translateX(0);
#airspeed-type-switch[data-value="false"]>.ol-switch-fill::before {
content: "CAS";
}
#altitude-type-switch[data-altitude-type="agl"]>.toggle-fill::after {
transform: translateX(calc(40px - 15px));
#unit-control-panel .ol-slider-value {
color: var(--accent-light-blue);
cursor: pointer;
font-size: 14px;
font-weight: bold;
}
#altitude-slider dt {
width: 40%;
#ai-on-off {
align-items: center;
display: grid;
grid-template-columns: 1.35fr 0.65fr ;
}
#altitude-slider dd {
#ai-on-off>*:nth-child(2) {
justify-self: end;
}
#ai-on-off>*:nth-child(3) {
color: var(--secondary-semitransparent-white);
}
#ai-on-off h4 {
margin: 0px;
}
#on-off-switch {
width: 60px;
height: 25px;
}
#on-off-switch>.ol-switch-fill {
background-color: var(--accent-light-blue);
}
#on-off-switch>.ol-switch-fill::after {
background-color: white;
}
#on-off-switch[data-value="true"]>.ol-switch-fill::before {
content: "ON";
}
#on-off-switch[data-value="false"]>.ol-switch-fill::before {
content: "OFF";
}
#advanced-settings-div {
display: flex;
column-gap: 5px;
width: 60%;
}
#altitude-slider dd>*:nth-child(2) {
width: 40px;
text-align: right;
}
#advanced-settings-div>*:nth-child(2) {
margin-left: auto;
}
#advanced-settings-div button {
height: 40px;
}
/* Element visibility control */
#unit-control-panel:not([data-show-categories-tooltip]) #categories-tooltip {
display: none;
}
#unit-control-panel:not([data-show-airspeed-slider]) #airspeed-slider {
display: none;
}
#unit-control-panel:not([data-show-altitude-slider]) #altitude-slider {
display: none;
}
#unit-control-panel:not([data-show-roe]) #roe {
display: none;
}
#unit-control-panel:not([data-show-threat]) #threat {
display: none;
}
#unit-control-panel:not([data-show-emissions-countermeasures]) #emissions-countermeasures {
display: none;
}
#unit-control-panel:not([data-show-on-off]) #ai-on-off {
display: none;
}
#unit-control-panel:not([data-show-advanced-settings-button]) #advanced-settings-button {
display: none;
}
#advanced-settings-dialog:not([data-show-settings]) #general-settings {
display: none;
}
#advanced-settings-dialog:not([data-show-tasking]) #tasking {
display: none;
}
#advanced-settings-dialog:not([data-show-tanker]) #tanker-checkbox {
display: none;
}
#advanced-settings-dialog:not([data-show-AWACS]) #AWACS-checkbox {
display: none;
}
#advanced-settings-dialog:not([data-show-TACAN]) #TACAN-options {
display: none;
}
#advanced-settings-dialog:not([data-show-radio]) #radio-options {
display: none;
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M459.1 52.4L442.6 6.5C440.7 2.6 436.5 0 432.1 0s-8.5 2.6-10.4 6.5L405.2 52.4l-46 16.8c-4.3 1.6-7.3 5.9-7.2 10.4c0 4.5 3 8.7 7.2 10.2l45.7 16.8 16.8 45.8c1.5 4.4 5.8 7.5 10.4 7.5s8.9-3.1 10.4-7.5l16.5-45.8 45.7-16.8c4.2-1.5 7.2-5.7 7.2-10.2c0-4.6-3-8.9-7.2-10.4L459.1 52.4zm-132.4 53c-12.5-12.5-32.8-12.5-45.3 0l-2.9 2.9C256.5 100.3 232.7 96 208 96C93.1 96 0 189.1 0 304S93.1 512 208 512s208-93.1 208-208c0-24.7-4.3-48.5-12.2-70.5l2.9-2.9c12.5-12.5 12.5-32.8 0-45.3l-80-80zM200 192c-57.4 0-104 46.6-104 104v8c0 8.8-7.2 16-16 16s-16-7.2-16-16v-8c0-75.1 60.9-136 136-136h8c8.8 0 16 7.2 16 16s-7.2 16-16 16h-8z"/></svg>

After

Width:  |  Height:  |  Size: 854 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M499.6 11.3c6.7-10.7 20.5-14.5 31.7-8.5s15.8 19.5 10.6 31L404.8 338.6c2.2 2.3 4.3 4.7 6.3 7.1l97.2-54.7c10.5-5.9 23.6-3.1 30.9 6.4s6.3 23-2.2 31.5l-87 87H378.5c-13.2-37.3-48.7-64-90.5-64s-77.4 26.7-90.5 64H117.8L42.3 363.7c-9.7-6.7-13.1-19.6-7.9-30.3s17.4-15.9 28.7-12.4l97.2 30.4c3-3.9 6.1-7.7 9.4-11.3L107.4 236.3c-6.1-10.1-3.9-23.1 5.1-30.7s22.2-7.5 31.1 .1L246 293.6c1.5-.4 3-.8 4.5-1.1l13.6-142.7c1.2-12.3 11.5-21.7 23.9-21.7s22.7 9.4 23.9 21.7l13.5 141.9L499.6 11.3zM64 448v0H512v0h32c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H64zM288 0c13.3 0 24 10.7 24 24V72c0 13.3-10.7 24-24 24s-24-10.7-24-24V24c0-13.3 10.7-24 24-24z"/></svg>

After

Width:  |  Height:  |  Size: 908 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M170.5 51.6L151.5 80h145l-19-28.4c-1.5-2.2-4-3.6-6.7-3.6H177.1c-2.7 0-5.2 1.3-6.7 3.6zm147-26.6L354.2 80H368h48 8c13.3 0 24 10.7 24 24s-10.7 24-24 24h-8V432c0 44.2-35.8 80-80 80H112c-44.2 0-80-35.8-80-80V128H24c-13.3 0-24-10.7-24-24S10.7 80 24 80h8H80 93.8l36.7-55.1C140.9 9.4 158.4 0 177.1 0h93.7c18.7 0 36.2 9.4 46.6 24.9zM80 128V432c0 17.7 14.3 32 32 32H336c17.7 0 32-14.3 32-32V128H80zm80 64V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16z"/></svg>

After

Width:  |  Height:  |  Size: 875 B

View File

@ -32,6 +32,8 @@
--secondary-dark-steel: #181e25;
--secondary-gunmetal-grey: #2f2f2f;
--secondary-light-grey: #797e83;
--secondary-semitransparent-white: #FFFFFFAA;
--secondary-transparent-white: #FFFFFF30;
--secondary-yellow: #ffd46893;
--background-hover: #f2f2f333;

View File

@ -24,7 +24,7 @@ export class AirbaseContextMenu extends ContextMenu {
this.setProperties(airbase.getProperties());
this.setParkings(airbase.getParkings());
this.setCoalition(airbase.getCoalition());
this.enableLandButton(getUnitsManager().getSelectedUnitsType() === "Aircraft" && (getUnitsManager().getSelectedUnitsCoalition() === airbase.getCoalition() || airbase.getCoalition() === "neutral"))
this.enableLandButton(getUnitsManager().getSelectedUnitsTypes().length == 1 && getUnitsManager().getSelectedUnitsTypes()[0] === "Aircraft" && (getUnitsManager().getSelectedUnitsCoalition() === airbase.getCoalition() || airbase.getCoalition() === "neutral"))
}
setName(airbaseName: string) {

View File

@ -0,0 +1,21 @@
export class Control {
#container: HTMLElement | null;
constructor(ID: string) {
this.#container = document.getElementById(ID);
}
show() {
if (this.#container != null)
this.#container.classList.remove("hide");
}
hide() {
if (this.#container != null)
this.#container.classList.add("hide");
}
getContainer() {
return this.#container;
}
}

View File

@ -1,50 +1,40 @@
export class Slider {
#container: HTMLElement | null;
import { zeroPad } from "../other/utils";
import { Control } from "./control";
export class Slider extends Control {
#callback: CallableFunction;
#slider: HTMLInputElement | null = null;
#valueText: HTMLElement | null = null;
#minValue: number;
#maxValue: number;
#increment: number;
#minValueDiv: HTMLElement | null = null;
#maxValueDiv: HTMLElement | null = null;
#minMaxValueDiv: HTMLElement | null = null;
#unit: string;
#display: string = "";
#dragged: boolean = false;
#value: number = 0;
constructor(ID: string, minValue: number, maxValue: number, unit: string, callback: CallableFunction) {
this.#container = document.getElementById(ID);
super(ID);
this.#callback = callback;
this.#minValue = minValue;
this.#maxValue = maxValue;
this.#increment = 1;
this.#unit = unit;
if (this.#container != null) {
this.#display = this.#container.style.display;
this.#slider = <HTMLInputElement>this.#container.querySelector("input");
if (this.#slider != null) {
this.#slider.addEventListener("input", (e: any) => this.#onInput());
this.#slider.addEventListener("mousedown", (e: any) => this.#onStart());
this.#slider.addEventListener("mouseup", (e: any) => this.#onFinalize());
}
this.#valueText = <HTMLElement>this.#container.querySelector("#value");
this.#slider = this.getContainer()?.querySelector("input") as HTMLInputElement;
if (this.#slider != null) {
this.#slider.addEventListener("input", (e: any) => this.#onInput());
this.#slider.addEventListener("mousedown", (e: any) => this.#onStart());
this.#slider.addEventListener("mouseup", (e: any) => this.#onFinalize());
}
}
show() {
if (this.#container != null)
this.#container.style.display = this.#display;
}
hide() {
if (this.#container != null)
this.#container.style.display = 'none';
this.#valueText = this.getContainer()?.querySelector(".ol-slider-value") as HTMLElement;
this.#minMaxValueDiv = this.getContainer()?.querySelector(".ol-slider-min-max") as HTMLElement;
}
setActive(newActive: boolean) {
if (this.#container && !this.#dragged) {
this.#container.classList.toggle("active", newActive);
if (!this.#dragged) {
this.getContainer()?.classList.toggle("active", newActive);
if (!newActive && this.#valueText != null)
this.#valueText.innerText = "Mixed values";
}
@ -54,6 +44,10 @@ export class Slider {
this.#minValue = newMinValue;
this.#maxValue = newMaxValue;
this.#updateMax();
if (this.#minMaxValueDiv != null) {
this.#minMaxValueDiv.setAttribute('data-min-value', `${this.#minValue}${this.#unit}`);
this.#minMaxValueDiv.setAttribute('data-max-value', `${this.#maxValue}${this.#unit}`);
}
}
setIncrement(newIncrement: number) {
@ -88,7 +82,16 @@ export class Slider {
#onValue() {
if (this.#valueText != null && this.#slider != null)
this.#valueText.innerText = this.#minValue + Math.round(parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue)) + this.#unit
{
var value = this.#minValue + Math.round(parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue));
var strValue = String(value);
if (value > 1000)
strValue = String(Math.floor(value / 1000)) + "," + zeroPad(value - Math.floor(value / 1000) * 1000, 3);
this.#valueText.innerText = strValue + " " + this.#unit.toUpperCase();
var percentValue = parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * 90 + 5;
this.#slider.style.background = 'linear-gradient(to right, var(--accent-light-blue) 5%, var(--accent-light-blue) ' + percentValue + '%, var(--background-grey) ' + percentValue + '%, var(--background-grey) 100%)'
}
this.setActive(true);
}

View File

@ -0,0 +1,34 @@
import { Control } from "./control";
export class Switch extends Control {
#value: boolean = false;
constructor(ID: string, initialValue?: boolean) {
super(ID);
this.getContainer()?.addEventListener('click', (e) => this.#onToggle());
this.setValue(initialValue !== undefined? initialValue: true);
/* Add the toggle itself to the document */
const container = this.getContainer();
if (container != undefined){
const width = getComputedStyle(container).width;
const height = getComputedStyle(container).height;
var el = document.createElement("div");
el.classList.add("ol-switch-fill");
el.style.setProperty("--width", width? width: "0px");
el.style.setProperty("--height", height? height: "0px");
this.getContainer()?.appendChild(el);
}
}
setValue(value: boolean) {
this.#value = value;
this.getContainer()?.setAttribute("data-value", String(value));
}
getValue() {
return this.#value;
}
#onToggle() {
this.setValue(!this.getValue());
}
}

View File

@ -15,6 +15,7 @@ import { keyEventWasInInput } from "./other/utils";
import { Popup } from "./popups/popup";
import { Dropdown } from "./controls/dropdown";
import { HotgroupPanel } from "./panels/hotgrouppanel";
import { SVGInjector } from "@tanem/svg-injector";
var map: Map;
@ -194,6 +195,15 @@ function setupEvents() {
location.reload();
})
document.querySelectorAll("[inject-svg]").forEach((el: Element) => {
var img = el as HTMLImageElement;
var isLoaded = img.complete && img.naturalHeight !== 0;
if (isLoaded)
SVGInjector(img);
else
img.onload = () => SVGInjector(img);
})
}
export function getMap() {

View File

@ -7,6 +7,7 @@ import { groundUnitsDatabase } from "../units/groundunitsdatabase";
import { Aircraft, GroundUnit, Unit } from "../units/unit";
import { UnitDatabase } from "../units/unitdatabase";
import { Panel } from "./panel";
import { Switch } from "../controls/switch";
const ROEs: string[] = ["Hold", "Return", "Designated", "Free"];
const reactionsToThreat: string[] = ["None", "Manoeuvre", "Passive", "Evade"];
@ -25,7 +26,10 @@ const altitudeIncrements: { [key: string]: number } = { Aircraft: 500, Helicopte
export class UnitControlPanel extends Panel {
#altitudeSlider: Slider;
#altitudeTypeSwitch: Switch;
#airspeedSlider: Slider;
#airspeedTypeSwitch: Switch;
#onOffSwitch: Switch;
#TACANXYDropdown: Dropdown;
#radioDecimalsDropdown: Dropdown;
#radioCallsignDropdown: Dropdown;
@ -40,22 +44,15 @@ export class UnitControlPanel extends Panel {
/* Unit control sliders */
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => {
this.#expectedAltitude = value;
getUnitsManager().selectedUnitsSetAltitude(value * 0.3048)
getUnitsManager().selectedUnitsSetAltitude(value * 0.3048);
});
this.#altitudeTypeSwitch = new Switch("altitude-type-switch");
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => {
this.#expectedSpeed = value;
getUnitsManager().selectedUnitsSetSpeed(value / 1.94384)
getUnitsManager().selectedUnitsSetSpeed(value / 1.94384);
});
this.getElement()?.querySelector("#altitude-type-switch")?.addEventListener('click', (e) => this.#onToggleAltitudeTypeSwitch(e));
/* Advanced settings dropdowns */
this.#TACANXYDropdown = new Dropdown("TACAN-XY", () => {});
this.#TACANXYDropdown.setOptions(["X", "Y"]);
this.#radioDecimalsDropdown = new Dropdown("radio-decimals", () => {});
this.#radioDecimalsDropdown.setOptions([".000", ".250", ".500", ".750"]);
this.#radioCallsignDropdown = new Dropdown("radio-callsign", () => {});
this.#airspeedTypeSwitch = new Switch("airspeed-type-switch");
/* Option buttons */
this.#optionButtons["ROE"] = ROEs.map((option: string, index: number) => {
@ -74,8 +71,20 @@ export class UnitControlPanel extends Panel {
this.getElement().querySelector("#reaction-to-threat-buttons-container")?.append(...this.#optionButtons["reactionToThreat"]);
this.getElement().querySelector("#emissions-countermeasures-buttons-container")?.append(...this.#optionButtons["emissionsCountermeasures"]);
/* On off switch */
this.#onOffSwitch = new Switch("on-off-switch");
/* Advanced settings dialog */
this.#advancedSettingsDialog = <HTMLElement> document.querySelector("#advanced-settings-dialog");
/* Advanced settings dropdowns */
this.#TACANXYDropdown = new Dropdown("TACAN-XY", () => {});
this.#TACANXYDropdown.setOptions(["X", "Y"]);
this.#radioDecimalsDropdown = new Dropdown("radio-decimals", () => {});
this.#radioDecimalsDropdown.setOptions([".000", ".250", ".500", ".750"]);
this.#radioCallsignDropdown = new Dropdown("radio-callsign", () => {});
/* Events and timer */
window.setInterval(() => {this.update();}, 25);
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => { this.show(); this.addButtons();});
@ -112,7 +121,7 @@ export class UnitControlPanel extends Panel {
var button = document.createElement("button");
var callsign = unit.getBaseData().unitName || "";
button.setAttribute("data-short-label", database?.getByName(unit.getBaseData().name)?.shortLabel || unit.getBaseData().name);
button.setAttribute("data-label", unit.getBaseData().name);
button.setAttribute("data-callsign", callsign);
button.setAttribute("data-coalition", unit.getMissionData().coalition);
@ -133,11 +142,53 @@ export class UnitControlPanel extends Panel {
update() {
if (this.getVisible()){
var units = getUnitsManager().getSelectedUnits();
this.getElement().querySelector("#advanced-settings-div")?.classList.toggle("hide", units.length != 1);
if (this.getElement() != null && units.length > 0) {
this.#showFlightControlSliders(units);
const element = this.getElement();
const units = getUnitsManager().getSelectedUnits();
const selectedUnitsTypes = getUnitsManager().getSelectedUnitsTypes();
if (element != null && units.length > 0) {
/* Toggle visibility of control elements */
element.toggleAttribute("data-show-categories-tooltip", selectedUnitsTypes.length > 1);
element.toggleAttribute("data-show-airspeed-slider", selectedUnitsTypes.length == 1);
element.toggleAttribute("data-show-altitude-slider", selectedUnitsTypes.length == 1 && (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")));
element.toggleAttribute("data-show-roe", true);
element.toggleAttribute("data-show-threat", (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")) && !(selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit")));
element.toggleAttribute("data-show-emissions-countermeasures", (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")) && !(selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit")));
element.toggleAttribute("data-show-on-off", (selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit")) && !(selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")));
element.toggleAttribute("data-show-advanced-settings-button", units.length == 1);
/* Flight controls */
var targetAltitude = getUnitsManager().getSelectedUnitsTargetAltitude();
var targetSpeed = getUnitsManager().getSelectedUnitsTargetSpeed();
if (selectedUnitsTypes.length == 1) {
this.#airspeedSlider.setMinMax(minSpeedValues[selectedUnitsTypes[0]], maxSpeedValues[selectedUnitsTypes[0]]);
this.#altitudeSlider.setMinMax(minAltitudeValues[selectedUnitsTypes[0]], maxAltitudeValues[selectedUnitsTypes[0]]);
this.#airspeedSlider.setIncrement(speedIncrements[selectedUnitsTypes[0]]);
this.#altitudeSlider.setIncrement(altitudeIncrements[selectedUnitsTypes[0]]);
this.#airspeedSlider.setActive(targetSpeed != undefined);
if (targetSpeed != undefined) {
targetSpeed *= 1.94384;
if (this.#updateCanSetSpeedSlider(targetSpeed)) {
this.#airspeedSlider.setValue(targetSpeed);
}
}
this.#altitudeSlider.setActive(targetAltitude != undefined);
if (targetAltitude != undefined) {
targetAltitude /= 0.3048;
if (this.#updateCanSetAltitudeSlider(targetAltitude)) {
this.#altitudeSlider.setValue(targetAltitude);
}
}
}
else {
this.#airspeedSlider.setActive(false);
this.#altitudeSlider.setActive(false);
}
/* Option buttons */
this.#optionButtons["ROE"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", units.every((unit: Unit) => unit.getOptionsData().ROE === button.value))
});
@ -170,54 +221,6 @@ export class UnitControlPanel extends Panel {
return false;
}
#showFlightControlSliders(units: Unit[]) {
if (getUnitsManager().getSelectedUnitsType() !== undefined)
this.#airspeedSlider.show()
else
this.#airspeedSlider.hide();
if (getUnitsManager().getSelectedUnitsType() === "Aircraft" || getUnitsManager().getSelectedUnitsType() === "Helicopter")
this.#altitudeSlider.show()
else
this.#altitudeSlider.hide();
this.getElement().querySelector(`#categories-tooltip`)?.classList.toggle("hide", getUnitsManager().getSelectedUnitsType() !== undefined);
var unitsType = getUnitsManager().getSelectedUnitsType();
var targetAltitude = getUnitsManager().getSelectedUnitsTargetAltitude();
var targetSpeed = getUnitsManager().getSelectedUnitsTargetSpeed();
if (unitsType != undefined) {
if (["GroundUnit", "NavyUnit"].includes(unitsType))
this.#altitudeSlider.hide()
this.#airspeedSlider.setMinMax(minSpeedValues[unitsType], maxSpeedValues[unitsType]);
this.#altitudeSlider.setMinMax(minAltitudeValues[unitsType], maxAltitudeValues[unitsType]);
this.#airspeedSlider.setIncrement(speedIncrements[unitsType]);
this.#altitudeSlider.setIncrement(altitudeIncrements[unitsType]);
this.#airspeedSlider.setActive(targetSpeed != undefined);
if (targetSpeed != undefined) {
targetSpeed *= 1.94384;
if (this.#updateCanSetSpeedSlider(targetSpeed)) {
this.#airspeedSlider.setValue(targetSpeed);
}
}
this.#altitudeSlider.setActive(targetAltitude != undefined);
if (targetAltitude != undefined) {
targetAltitude /= 0.3048;
if (this.#updateCanSetAltitudeSlider(targetAltitude)) {
this.#altitudeSlider.setValue(targetAltitude);
}
}
}
else {
this.#airspeedSlider.setActive(false);
this.#altitudeSlider.setActive(false);
}
}
#updateAdvancedSettingsDialog(units: Unit[])
{
if (units.length == 1)
@ -356,10 +359,4 @@ export class UnitControlPanel extends Panel {
button.addEventListener("click", callback);
return button;
}
#onToggleAltitudeTypeSwitch(e: any) {
const altitudeType = this.getElement()?.querySelector("#altitude-type-switch")?.getAttribute("data-altitude-type");
var newAltitudeType = altitudeType == "asl"? "agl": "asl";
this.getElement()?.querySelector("#altitude-type-switch")?.setAttribute("data-altitude-type", newAltitudeType);
}
}

View File

@ -560,7 +560,7 @@ export class Unit extends CustomMarker {
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().length == 1 && (getUnitsManager().getSelectedUnits().includes(this)))) {
options["attack"] = {text: "Attack", tooltip: "Attack the unit using A/A or A/G weapons"};
if (getUnitsManager().getSelectedUnitsType() === "Aircraft")
if (getUnitsManager().getSelectedUnitsTypes().length == 1 && getUnitsManager().getSelectedUnitsTypes()[0] === "Aircraft")
options["follow"] = {text: "Follow", tooltip: "Follow the unit at a user defined distance and position"};;
}
else if ((getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this))) || getUnitsManager().getSelectedUnits().length == 0) {

View File

@ -145,13 +145,13 @@ export class UnitsManager {
this.getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setSelected(true))
}
getSelectedUnitsType() {
getSelectedUnitsTypes() {
if (this.getSelectedUnits().length == 0)
return undefined;
return [];
return this.getSelectedUnits().map((unit: Unit) => {
return unit.constructor.name
})?.reduce((a: any, b: any) => {
return a == b ? a : undefined
})?.filter((value: any, index: any, array: string[]) => {
return array.indexOf(value) === index;
});
};

View File

@ -1,8 +1,8 @@
<div id="map-contextmenu" oncontextmenu="return false;">
<div id="active-coalition-label" data-active-coalition="blue"></div>
<div id="upper-bar" class="ol-panel">
<label id="context-menu-switch" class="toggle" for="context-menu-toggle">
<div data-active-coalition="blue" class="toggle-fill"></div>
<label id="context-menu-switch" class="ol-switch" for="context-menu-ol-switch">
<div data-active-coalition="blue" class="ol-switch-fill"></div>
</label>
<button data-active-coalition="blue" id="aircraft-spawn-button" title="Spawn aircraft" data-on-click="contextMenuShow"
data-on-click-params='{ "type": "aircraft" }' class="unit-spawn-button"></button>

View File

@ -1,4 +1,4 @@
<div id="unit-control-panel" class="ol-panel ol-panel-padding-lg" oncontextmenu="return false;">
<div id="unit-control-panel" class="ol-panel ol-panel-padding-lg" oncontextmenu="return false;">
<h3>Selected Units</h3>
@ -6,65 +6,73 @@
<div id="selected-units-container" class="ol-scrollable">
<!-- This is where all the unit selection buttons will be shown-->
<!-- <button class="pill highlight-coalition" data-coalition="blue" data-short-label="18">Olympus 1-1</button> -->
<!-- <button class="pill highlight-coalition" data-coalition="blue" data-label="18">Olympus 1-1</button> -->
</div>
</div>
<hr />
<hr />
<div id="flight-data">
<h4>Flight controls</h4>
<div class="slider-container flight-control-slider" id="airspeed-slider">
<dl class="ol-data-grid">
<dt>Speed</dt>
<dd class="flight-control-value" id="value"></dd>
</dl>
<input type="range" min="0" max="100" value="0" class="slider">
</div>
<div class="slider-container flight-control-slider" id="altitude-slider">
<dl class="ol-data-grid">
<dt> Altitude
</dt>
<dd>
<label id="altitude-type-switch" class="toggle" data-altitude-type="agl">
<div class="toggle-fill"></div>
</label>
<div class="flight-control-value" id="value"></div>
</dd>
</dl>
<input type="range" min="0" max="100" value="0" class="slider">
</div>
<h5 id="categories-tooltip" class="hide">Multiple categories selected</h5>
<div id="flight-data">
<h4>Controls</h4>
<div id="airspeed-slider" class="ol-slider-container flight-control-ol-slider">
<dl class="ol-data-grid">
<dt>Speed</dt>
<dd>
<div class="ol-slider-value"></div>
<div id="airspeed-type-switch" class="ol-switch"></div>
</dd>
</dl>
<input type="range" min="0" max="100" value="0" class="ol-slider">
<div class="ol-slider-min-max"></div>
</div>
<div id="altitude-slider" class="ol-slider-container flight-control-ol-slider">
<dl class="ol-data-grid">
<dt> Altitude
</dt>
<dd>
<div class="ol-slider-value"></div>
<div id="altitude-type-switch" class="ol-switch"></div>
</dd>
</dl>
<input type="range" min="0" max="100" value="0" class="ol-slider">
<div class="ol-slider-min-max"></div>
</div>
<h5 id="categories-tooltip">Multiple categories selected</h5>
</div>
<div id="roe">
<h4>Rules of engagement</h4>
<div id="roe-buttons-container" class="ol-group ol-button-box ol-option-button">
<!-- This is where the roe buttons will be shown -->
<!-- This is where the roe buttons will be shown -->
</div>
</div>
<div id="threat">
<h4>Reaction to threat</h4>
<div id="reaction-to-threat-buttons-container" class="ol-group ol-button-box ol-option-button">
<!-- This is where the reaction to threat buttons will be shown -->
<!-- This is where the reaction to threat buttons will be shown -->
</div>
</div>
<div id="emissions-countermeasures">
<h4>Radar & ECM</h4>
<div id="emissions-countermeasures-buttons-container" class="ol-group ol-button-box ol-option-button">
<!-- This is where the emissions/countermeasures buttons will be shown -->
<!-- This is where the emissions/countermeasures buttons will be shown -->
</div>
</div>
<div id="ai-on-off">
<h4>Unit active</h4>
<div id="on-off-switch" class="ol-switch"></div>
<div>Toggling this disables unit AI completely. It will no longer move, react or emit radio waves.</div>
</div>
<hr />
<div id="advanced-settings-div">
<button id="advanced-settings-button" class="ol-button-settings" data-on-click="showAdvancedSettings">Adjust settings</button>
<hr />
<button id="advanced-settings-button" class="ol-button-settings" data-on-click="showAdvancedSettings">Settings</button>
<button class="ol-button-warning" data-on-click="deleteSelectedUnits"><img src="/resources/theme/images/icons/trash-can-regular.svg" inject-svg>Delete</button>
<button class="ol-button-warning" data-on-click="explodeSelectedUnits"><img src="/resources/theme/images/icons/explosion-solid.svg" inject-svg></button>
</div>
<button class="ol-button-warning" data-on-click="deleteSelectedUnits">Delete unit</button>
</div>
</div>