import { sendToMain } from "../../renderer/sendToMain.js"; import { AbstractStateSubscriberWebComponent } from "../util/AbstractStateSubscriberWebComponent.js"; import { registerElement } from "../../renderer/registerElement.js"; export type FuelPayloadWebComponentState = { fuelMass: number; payloadMass: number; }; export class FuelPayloadWebComponent extends AbstractStateSubscriberWebComponent { private isInitialized = false; private maximumTakeoffMassKg = 0; private elements!: { fuelMass: HTMLInputElement; fuelMassMax: HTMLSpanElement; payloadMass: HTMLInputElement; payloadMassMax: HTMLSpanElement; persons: HTMLInputElement; personsMax: HTMLSpanElement; range: HTMLInputElement; rangeMax: HTMLSpanElement; }; private weightProPerson_kg = 84; private initialize() { this.setAttribute("aria-role", "region"); this.innerHTML = `\

 Fuel / payload

kg
NM
kg
`; this.elements = { fuelMass: this.querySelector("#fuelloadsetting-fuelmass") as HTMLInputElement, fuelMassMax: document.querySelector("label[for='fuelloadsetting-fuelmass'] span") as HTMLSpanElement, payloadMass: this.querySelector("#fuelloadsetting-payloadmass") as HTMLInputElement, payloadMassMax: document.querySelector("label[for='fuelloadsetting-payloadmass'] span") as HTMLSpanElement, persons: this.querySelector("#fuelloadsetting-persons") as HTMLInputElement, personsMax: document.querySelector("label[for='fuelloadsetting-persons'] span") as HTMLSpanElement, range: this.querySelector("#fuelloadsetting-range") as HTMLInputElement, rangeMax: document.querySelector("label[for='fuelloadsetting-range'] span") as HTMLSpanElement, }; } get state(): FuelPayloadWebComponentState { return { fuelMass: this.elements.fuelMass.valueAsNumber || 0, payloadMass: (this.elements.payloadMass.valueAsNumber || 0) + (this.elements.persons.valueAsNumber || 0) * this.weightProPerson_kg, }; } connectedCallback() { if (!this.isInitialized) { this.initialize(); this.isInitialized = true; } this.elements.range.addEventListener("input", this.handleRangeChange); this.subscribeToStateUpdates((state) => { const fuelMassMax = Math.floor(state.aircraftData?.maximumFuelMassKg ?? 0); const maxRange = Math.floor(state.aircraftData?.maximumRangeNm ?? 0); const maxPersons = Math.min( state.aircraftData?.maximumPersonsOnBoard ?? Infinity, Math.floor(state.getMaxRemainingPayload_kg / this.weightProPerson_kg), ); const personsMass = this.getPersonMass(); const maxPayload = Math.floor(state.getMaxRemainingPayload_kg - personsMass); const payloadMass = Math.max(0, Math.floor(state.aeroflyFlight.fuelLoadSetting.payloadMass - personsMass)); this.maximumTakeoffMassKg = state.aircraftData?.maximumTakeoffMassKg ?? 1; const calculateRange = (fuelMass: number) => maxRange * (fuelMass / (fuelMassMax || 1)) * (1 - state.aeroflyFlight.fuelLoadSetting.payloadMass / this.maximumTakeoffMassKg); const calculatedRange = calculateRange(state.aeroflyFlight.fuelLoadSetting.fuelMass), lowerBound = calculateRange(state.aeroflyFlight.fuelLoadSetting.fuelMass - 1), upperBound = calculateRange(state.aeroflyFlight.fuelLoadSetting.fuelMass + 1); /*console.log({ lowerBound, valueAsNumber: this.elements.range.valueAsNumber, upperBound, calculatedRange, });*/ // ---------------------------------- this.elements.fuelMass.valueAsNumber = Math.floor(state.aeroflyFlight.fuelLoadSetting.fuelMass); this.elements.fuelMass.max = fuelMassMax.toFixed(); this.elements.fuelMass.disabled = this.elements.fuelMass.max === "0"; this.elements.fuelMassMax.textContent = fuelMassMax ? `(max. ${this.numberFormat(fuelMassMax)} kg)` : ""; // TODO: Only change range slider if slider value could not have been created from the given fuel mass if (lowerBound > this.elements.range.valueAsNumber || upperBound < this.elements.range.valueAsNumber) { this.elements.range.valueAsNumber = Math.floor(calculatedRange); } this.elements.range.classList.toggle( "input-warning", this.elements.range.valueAsNumber < state.route.distance_nm, ); this.title = `Recommended minimal range: ${state.route.distance_nm.toFixed()} NM`; this.elements.range.max = maxRange.toFixed(); this.elements.range.disabled = this.elements.range.max === "0" || this.elements.fuelMass.max === "0"; this.elements.rangeMax.textContent = maxRange ? `(max. ${this.numberFormat(maxRange)} NM)` : ""; this.elements.payloadMass.valueAsNumber = payloadMass; this.elements.payloadMass.max = maxPayload.toFixed(); this.elements.payloadMass.disabled = this.elements.payloadMass.max === "0"; this.elements.payloadMassMax.textContent = state.getMaxRemainingPayload_kg ? `(max. ${this.numberFormat(maxPayload)} kg)` : ""; this.elements.persons.classList.toggle( "input-warning", this.elements.persons.valueAsNumber < 1 && this.elements.payloadMass.valueAsNumber < this.weightProPerson_kg, ); this.elements.persons.max = maxPersons.toFixed(); this.elements.persons.disabled = this.elements.persons.max === "0"; this.elements.personsMax.textContent = state.getMaxRemainingPayload_kg ? `(max. ${this.numberFormat(maxPersons)})` : ""; }); this.addEventListener("input", this.handleChange); } disconnectedCallback(): void { super.disconnectedCallback(); this.elements.range.removeEventListener("input", this.handleRangeChange); this.removeEventListener("input", this.handleChange); } private handleRangeChange = () => { const range = this.elements.range.valueAsNumber; if (range < 1) { this.elements.fuelMass.valueAsNumber = 0; return; } const maxRange = parseFloat(this.elements.range.max); if (maxRange > 0) { const divider = 1 - (this.elements.payloadMass.valueAsNumber + this.getPersonMass()) / this.maximumTakeoffMassKg || 1; const fuelMass = Math.ceil(((range / maxRange) * parseFloat(this.elements.fuelMass.max)) / divider); this.elements.fuelMass.valueAsNumber = fuelMass; } }; private getPersonMass() { return this.elements.persons.valueAsNumber * this.weightProPerson_kg; } private handleChange = () => { sendToMain("fuel-payload:set", this.state); }; private numberFormat(value: number): string { return new Intl.NumberFormat(document.documentElement.lang, { minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(value); } static registerElement() { registerElement("startgeraet-fuel-payload", FuelPayloadWebComponent); } }