mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added switch toggle
This commit is contained in:
@@ -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) {
|
||||
|
||||
21
client/src/controls/control.ts
Normal file
21
client/src/controls/control.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
34
client/src/controls/switch.ts
Normal file
34
client/src/controls/switch.ts
Normal 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());
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user