Completed frontend controls

This commit is contained in:
Pax1601
2023-06-01 17:18:14 +02:00
parent 4087dbde21
commit 1dd4014e61
29 changed files with 1297 additions and 541 deletions

View File

@@ -1,5 +1,6 @@
export class Control {
#container: HTMLElement | null;
expectedValue: any = null;
constructor(ID: string) {
this.#container = document.getElementById(ID);
@@ -18,4 +19,16 @@ export class Control {
getContainer() {
return this.#container;
}
setExpectedValue(expectedValue: any) {
this.expectedValue = expectedValue;
}
resetExpectedValue() {
this.expectedValue = null;
}
checkExpectedValue(value: any) {
return this.expectedValue === null || value === this.expectedValue;
}
}

View File

@@ -19,14 +19,12 @@ export class Dropdown {
}
this.#value.addEventListener("click", (ev) => {
this.#element.classList.toggle("is-open");
this.#options.classList.toggle("scrollbar-visible", this.#options.scrollHeight > this.#options.clientHeight);
this.#clip();
this.#toggle();
});
document.addEventListener("click", (ev) => {
if (!(this.#value.contains(ev.target as Node) || this.#options.contains(ev.target as Node) || this.#element.contains(ev.target as Node))) {
this.#element.classList.remove("is-open");
this.#close();
}
});
@@ -46,12 +44,7 @@ export class Dropdown {
button.addEventListener("click", (e: MouseEvent) => {
e.stopPropagation();
this.#value = document.createElement("div");
this.#value.classList.add("ol-ellipsed");
this.#value.innerText = option;
this.#close();
this.#callback(option, e);
this.#index = idx;
this.selectValue(idx);
});
return div;
}));
@@ -113,6 +106,8 @@ export class Dropdown {
#open() {
this.#element.classList.add("is-open");
this.#options.classList.toggle("scrollbar-visible", this.#options.scrollHeight > this.#options.clientHeight);
this.#clip();
}
#toggle() {

View File

@@ -5,6 +5,8 @@ import { aircraftDatabase } from "../units/aircraftdatabase";
import { groundUnitsDatabase } from "../units/groundunitsdatabase";
import { ContextMenu } from "./contextmenu";
import { Dropdown } from "./dropdown";
import { Switch } from "./switch";
import { Slider } from "./slider";
export interface SpawnOptions {
role: string;
@@ -13,24 +15,29 @@ export interface SpawnOptions {
coalition: string;
loadout: string | null;
airbaseName: string | null;
altitude: number | null;
}
export class MapContextMenu extends ContextMenu {
#coalitionSwitch: Switch;
#aircraftRoleDropdown: Dropdown;
#aircraftTypeDropdown: Dropdown;
#aircraftLoadoutDropdown: Dropdown;
#aircrafSpawnAltitudeSlider: Slider;
#groundUnitRoleDropdown: Dropdown;
#groundUnitTypeDropdown: Dropdown;
#spawnOptions: SpawnOptions = { role: "", type: "", latlng: new LatLng(0, 0), loadout: null, coalition: "blue", airbaseName: null };
#spawnOptions: SpawnOptions = { role: "", type: "", latlng: new LatLng(0, 0), loadout: null, coalition: "blue", airbaseName: null, altitude: 20000 };
constructor(id: string) {
super(id);
this.getContainer()?.querySelector("#context-menu-switch")?.addEventListener('click', (e) => this.#onToggleLeftClick(e));
this.getContainer()?.querySelector("#context-menu-switch")?.addEventListener('contextmenu', (e) => this.#onToggleRightClick(e));
this.#coalitionSwitch = new Switch("coalition-switch", this.#onSwitchClick);
this.#coalitionSwitch.setValue(false);
this.#coalitionSwitch.getContainer()?.addEventListener("contextmenu", (e) => this.#onSwitchRightClick(e));
this.#aircraftRoleDropdown = new Dropdown("aircraft-role-options", (role: string) => this.#setAircraftRole(role));
this.#aircraftTypeDropdown = new Dropdown("aircraft-type-options", (type: string) => this.#setAircraftType(type));
this.#aircraftLoadoutDropdown = new Dropdown("loadout-options", (loadout: string) => this.#setAircraftLoadout(loadout));
this.#aircrafSpawnAltitudeSlider = new Slider("aircraft-spawn-altitude-slider", 0, 50000, "ft", (value: number) => {this.#spawnOptions.altitude = value;});
this.#groundUnitRoleDropdown = new Dropdown("ground-unit-role-options", (role: string) => this.#setGroundUnitRole(role));
this.#groundUnitTypeDropdown = new Dropdown("ground-unit-type-options", (type: string) => this.#setGroundUnitType(type));
@@ -61,6 +68,10 @@ export class MapContextMenu extends ContextMenu {
spawnSmoke(e.detail.color, this.getLatLng());
});
this.#aircrafSpawnAltitudeSlider.setIncrement(500);
this.#aircrafSpawnAltitudeSlider.setValue(20000);
this.#aircrafSpawnAltitudeSlider.setActive(true);
this.hide();
}
@@ -102,26 +113,13 @@ export class MapContextMenu extends ContextMenu {
this.#spawnOptions.latlng = latlng;
}
#onToggleLeftClick(e: any) {
if (this.getContainer() != null) {
if (e.srcElement.dataset.activeCoalition == "blue")
setActiveCoalition("neutral");
else if (e.srcElement.dataset.activeCoalition == "neutral")
setActiveCoalition("red");
else
setActiveCoalition("blue");
}
#onSwitchClick(value: boolean) {
value? setActiveCoalition("red"): setActiveCoalition("blue");
}
#onToggleRightClick(e: any) {
if (this.getContainer() != null) {
if (e.srcElement.dataset.activeCoalition == "red")
setActiveCoalition("neutral");
else if (e.srcElement.dataset.activeCoalition == "neutral")
setActiveCoalition("blue");
else
setActiveCoalition("red");
}
#onSwitchRightClick(e: any) {
this.#coalitionSwitch.setValue(undefined);
setActiveCoalition("neutral");
}
/********* Aircraft spawn menu *********/

View File

@@ -2,38 +2,38 @@ import { zeroPad } from "../other/utils";
import { Control } from "./control";
export class Slider extends Control {
#callback: CallableFunction;
#callback: CallableFunction | null = null;
#slider: HTMLInputElement | null = null;
#valueText: HTMLElement | null = null;
#minValue: number;
#maxValue: number;
#increment: number;
#minValue: number = 0;
#maxValue: number = 0;
#increment: number = 0;
#minMaxValueDiv: HTMLElement | null = null;
#unit: string;
#unitOfMeasure: string;
#dragged: boolean = false;
#value: number = 0;
constructor(ID: string, minValue: number, maxValue: number, unit: string, callback: CallableFunction) {
constructor(ID: string, minValue: number, maxValue: number, unitOfMeasure: string, callback: CallableFunction) {
super(ID);
this.#callback = callback;
this.#minValue = minValue;
this.#maxValue = maxValue;
this.#increment = 1;
this.#unit = unit;
this.#callback = callback;
this.#unitOfMeasure = unitOfMeasure;
this.#slider = this.getContainer()?.querySelector("input") as HTMLInputElement;
if (this.#slider != null) {
this.#slider.addEventListener("input", (e: any) => this.#onInput());
this.#slider.addEventListener("input", (e: any) => this.#update());
this.#slider.addEventListener("mousedown", (e: any) => this.#onStart());
this.#slider.addEventListener("mouseup", (e: any) => this.#onFinalize());
}
this.#valueText = this.getContainer()?.querySelector(".ol-slider-value") as HTMLElement;
this.#minMaxValueDiv = this.getContainer()?.querySelector(".ol-slider-min-max") as HTMLElement;
this.setIncrement(1);
this.setMinMax(minValue, maxValue);
}
setActive(newActive: boolean) {
if (!this.#dragged) {
if (!this.getDragged()) {
this.getContainer()?.classList.toggle("active", newActive);
if (!newActive && this.#valueText != null)
this.#valueText.innerText = "Mixed values";
@@ -41,27 +41,31 @@ export class Slider extends Control {
}
setMinMax(newMinValue: number, newMaxValue: number) {
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}`);
if (this.#minValue != newMinValue || this.#maxValue != newMaxValue) {
this.#minValue = newMinValue;
this.#maxValue = newMaxValue;
this.#updateMaxValue();
if (this.#minMaxValueDiv != null) {
this.#minMaxValueDiv.setAttribute('data-min-value', `${this.#minValue}${this.#unitOfMeasure}`);
this.#minMaxValueDiv.setAttribute('data-max-value', `${this.#maxValue}${this.#unitOfMeasure}`);
}
}
}
setIncrement(newIncrement: number) {
this.#increment = newIncrement;
this.#updateMax();
if (this.#increment != newIncrement) {
this.#increment = newIncrement;
this.#updateMaxValue();
}
}
setValue(newValue: number) {
// Disable value setting if the user is dragging the element
if (!this.#dragged) {
setValue(newValue: number, ignoreExpectedValue: boolean = true) {
if (!this.getDragged() && (ignoreExpectedValue || this.checkExpectedValue(newValue))) {
this.#value = newValue;
if (this.#slider != null)
this.#slider.value = String((newValue - this.#minValue) / (this.#maxValue - this.#minValue) * parseFloat(this.#slider.max));
this.#onValue()
this.#update();
}
}
@@ -69,45 +73,51 @@ export class Slider extends Control {
return this.#value;
}
setDragged(newDragged: boolean) {
this.#dragged = newDragged;
}
getDragged() {
return this.#dragged;
}
#updateMax() {
#updateMaxValue() {
var oldValue = this.getValue();
if (this.#slider != null)
this.#slider.max = String((this.#maxValue - this.#minValue) / this.#increment);
this.setValue(oldValue);
}
#onValue() {
#update() {
if (this.#valueText != null && this.#slider != null)
{
/* Update the text value */
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();
this.#valueText.innerText = `${strValue} ${this.#unitOfMeasure.toUpperCase()}`;
/* Update the position of the slider */
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.#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);
}
#onInput() {
this.#onValue();
}
#onStart() {
this.#dragged = true;
this.setDragged(true);
}
#onFinalize() {
this.#dragged = false;
this.setDragged(false);
if (this.#slider != null) {
this.#value = this.#minValue + parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue);
this.#callback(this.getValue());
this.resetExpectedValue();
this.setValue(this.#minValue + parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue));
if (this.#callback) {
this.#callback(this.getValue());
this.setExpectedValue(this.getValue());
}
}
}
}

View File

@@ -1,12 +1,16 @@
import { Control } from "./control";
export class Switch extends Control {
#value: boolean = false;
constructor(ID: string, initialValue?: boolean) {
#value: boolean | undefined = false;
#callback: CallableFunction | null = null;
constructor(ID: string, callback: CallableFunction, initialValue?: boolean) {
super(ID);
this.getContainer()?.addEventListener('click', (e) => this.#onToggle());
this.setValue(initialValue !== undefined? initialValue: true);
this.#callback = callback;
/* Add the toggle itself to the document */
const container = this.getContainer();
if (container != undefined){
@@ -14,14 +18,17 @@ export class Switch extends Control {
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");
el.style.setProperty("--width", width? width: "0");
el.style.setProperty("--height", height? height: "0");
this.getContainer()?.appendChild(el);
}
}
setValue(value: boolean) {
this.#value = value;
this.getContainer()?.setAttribute("data-value", String(value));
setValue(newValue: boolean | undefined, ignoreExpectedValue: boolean = true) {
if (ignoreExpectedValue || this.checkExpectedValue(newValue)) {
this.#value = newValue;
this.getContainer()?.setAttribute("data-value", String(newValue));
}
}
getValue() {
@@ -29,6 +36,11 @@ export class Switch extends Control {
}
#onToggle() {
this.resetExpectedValue();
this.setValue(!this.getValue());
if (this.#callback) {
this.#callback(this.getValue());
this.setExpectedValue(this.getValue());
}
}
}