More svg injection, removing stringed html from code

This commit is contained in:
Pax1601
2023-05-24 08:21:04 +02:00
parent a2664dc676
commit e7ce9ac76d
123 changed files with 1439 additions and 1829 deletions

View File

@@ -8,7 +8,7 @@ interface AirbasesData {
}
interface BullseyesData {
bullseyes: {[key: string]: any},
bullseyes: {[key: string]: {latitude: number, longitude: number, coalition: string}},
}
interface LogData {

View File

@@ -5,8 +5,7 @@ import { ContextMenu } from "./contextmenu";
export class AirbaseContextMenu extends ContextMenu {
#airbase: Airbase | null = null;
constructor(id: string)
{
constructor(id: string) {
super(id);
document.addEventListener("contextMenuSpawnAirbase", (e: any) => {
this.showSpawnMenu();
@@ -19,8 +18,7 @@ export class AirbaseContextMenu extends ContextMenu {
})
}
setAirbase(airbase: Airbase)
{
setAirbase(airbase: Airbase) {
this.#airbase = airbase;
this.setName(airbase.getName());
this.setProperties(airbase.getProperties());
@@ -29,24 +27,21 @@ export class AirbaseContextMenu extends ContextMenu {
this.enableLandButton(getUnitsManager().getSelectedUnitsType() === "Aircraft" && (getUnitsManager().getSelectedUnitsCoalition() === airbase.getCoalition() || airbase.getCoalition() === "neutral"))
}
setName(airbaseName: string)
{
setName(airbaseName: string) {
var nameDiv = <HTMLElement>this.getContainer()?.querySelector("#airbase-name");
if (nameDiv != null)
nameDiv.innerText = airbaseName;
nameDiv.innerText = airbaseName;
}
setProperties(airbaseProperties: string[])
{
setProperties(airbaseProperties: string[]) {
this.getContainer()?.querySelector("#airbase-properties")?.replaceChildren(...airbaseProperties.map((property: string) => {
var div = document.createElement("div");
div.innerText = property;
return div;
}), );
}),);
}
setParkings(airbaseParkings: string[])
{
setParkings(airbaseParkings: string[]) {
this.getContainer()?.querySelector("#airbase-parking")?.replaceChildren(...airbaseParkings.map((parking: string) => {
var div = document.createElement("div");
div.innerText = parking;
@@ -54,22 +49,18 @@ export class AirbaseContextMenu extends ContextMenu {
}));
}
setCoalition(coalition: string)
{
setCoalition(coalition: string) {
(<HTMLElement>this.getContainer()?.querySelector("#spawn-airbase-aircraft-button")).dataset.activeCoalition = coalition;
}
enableLandButton(enableLandButton: boolean)
{
enableLandButton(enableLandButton: boolean) {
this.getContainer()?.querySelector("#land-here-button")?.classList.toggle("hide", !enableLandButton);
}
showSpawnMenu()
{
if (this.#airbase != null)
{
showSpawnMenu() {
if (this.#airbase != null) {
setActiveCoalition(this.#airbase.getCoalition());
getMap().showMapContextMenu({originalEvent: {x: this.getX(), y: this.getY(), latlng: this.getLatLng()}});
getMap().showMapContextMenu({ originalEvent: { x: this.getX(), y: this.getY(), latlng: this.getLatLng() } });
getMap().getMapContextMenu().hideUpperBar();
getMap().getMapContextMenu().showSubMenu("aircraft");
getMap().getMapContextMenu().setAirbaseName(this.#airbase.getName());

View File

@@ -23,28 +23,23 @@ export class ContextMenu {
this.#container?.classList.toggle("hide", true);
}
getContainer()
{
getContainer() {
return this.#container;
}
getLatLng()
{
getLatLng() {
return this.#latlng;
}
getX()
{
getX() {
return this.#x;
}
getY()
{
getY() {
return this.#y;
}
clip()
{
clip() {
if (this.#container != null) {
if (this.#x + this.#container.offsetWidth < window.innerWidth)
this.#container.style.left = this.#x + "px";

View File

@@ -7,17 +7,16 @@ export class Dropdown {
#optionsList: string[] = [];
#index: number = 0;
constructor(ID: string, callback: CallableFunction, options: string[] | null = null)
{
this.#element = <HTMLElement>document.getElementById(ID);
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
constructor(ID: string, callback: CallableFunction, options: string[] | null = null) {
this.#element = <HTMLElement>document.getElementById(ID);
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
this.#defaultValue = this.#value.innerText;
this.#callback = callback;
this.#callback = callback;
if (options != null) {
this.setOptions(options);
}
}
this.#value.addEventListener("click", (ev) => {
this.#element.classList.toggle("is-open");
@@ -31,11 +30,10 @@ export class Dropdown {
}
});
this.#options.classList.add( "ol-scrollable" );
this.#options.classList.add("ol-scrollable");
}
setOptions(optionsList: string[])
{
setOptions(optionsList: string[]) {
this.#optionsList = optionsList;
this.#options.replaceChildren(...optionsList.map((option: string, idx: number) => {
var div = document.createElement("div");
@@ -48,7 +46,9 @@ export class Dropdown {
button.addEventListener("click", (e: MouseEvent) => {
e.stopPropagation();
this.#value.innerHTML = `<div class = "ol-ellipsed"> ${option} </div>`;
this.#value = document.createElement("div");
this.#value.classList.add("ol-ellipsed");
this.#value.innerText = option;
this.#close();
this.#callback(option, e);
this.#index = idx;
@@ -57,19 +57,15 @@ export class Dropdown {
}));
}
selectText( text:string ) {
const index = [].slice.call( this.#options.children ).findIndex( ( opt:Element ) => opt.querySelector( "button" )?.innerText === text );
if ( index > -1 ) {
this.selectValue( index );
selectText(text: string) {
const index = [].slice.call(this.#options.children).findIndex((opt: Element) => opt.querySelector("button")?.innerText === text);
if (index > -1) {
this.selectValue(index);
}
}
selectValue(idx: number)
{
if (idx < this.#optionsList.length)
{
selectValue(idx: number) {
if (idx < this.#optionsList.length) {
var option = this.#optionsList[idx];
this.#value.innerHTML = `<div class = "ol-ellipsed"> ${option} </div>`;
this.#index = idx;
@@ -91,8 +87,8 @@ export class Dropdown {
}
setValue(value: string) {
var index = this.#optionsList.findIndex((option) => {return option === value});
if (index > -1)
var index = this.#optionsList.findIndex((option) => { return option === value });
if (index > -1)
this.selectValue(index);
}
@@ -102,21 +98,21 @@ export class Dropdown {
#clip() {
const options = this.#options;
const bounds = options.getBoundingClientRect();
this.#element.dataset.position = ( bounds.bottom > window.innerHeight ) ? "top" : "";
const bounds = options.getBoundingClientRect();
this.#element.dataset.position = (bounds.bottom > window.innerHeight) ? "top" : "";
}
#close() {
this.#element.classList.remove( "is-open" );
this.#element.classList.remove("is-open");
this.#element.dataset.position = "";
}
#open() {
this.#element.classList.add( "is-open" );
this.#element.classList.add("is-open");
}
#toggle() {
if ( this.#element.classList.contains( "is-open" ) ) {
if (this.#element.classList.contains("is-open")) {
this.#close();
} else {
this.#open();

View File

@@ -41,8 +41,7 @@ export class MapContextMenu extends ContextMenu {
document.addEventListener("contextMenuDeployAircraft", () => {
this.hide();
this.#spawnOptions.coalition = getActiveCoalition();
if (this.#spawnOptions)
{
if (this.#spawnOptions) {
getMap().addTemporaryMarker(this.#spawnOptions.latlng);
spawnAircraft(this.#spawnOptions);
}
@@ -51,8 +50,7 @@ export class MapContextMenu extends ContextMenu {
document.addEventListener("contextMenuDeployGroundUnit", () => {
this.hide();
this.#spawnOptions.coalition = getActiveCoalition();
if (this.#spawnOptions)
{
if (this.#spawnOptions) {
getMap().addTemporaryMarker(this.#spawnOptions.latlng);
spawnGroundUnit(this.#spawnOptions);
}
@@ -189,10 +187,10 @@ export class MapContextMenu extends ContextMenu {
this.#spawnOptions.role = role;
this.#resetGroundUnitType();
const types = groundUnitsDatabase.getByRole(role).map((blueprint) => { return blueprint.label } );
const types = groundUnitsDatabase.getByRole(role).map((blueprint) => { return blueprint.label });
types.sort();
this.#groundUnitTypeDropdown.setOptions( types );
this.#groundUnitTypeDropdown.setOptions(types);
this.#groundUnitTypeDropdown.selectValue(0);
this.clip();
}
@@ -205,8 +203,8 @@ export class MapContextMenu extends ContextMenu {
const roles = groundUnitsDatabase.getRoles();
roles.sort();
this.#groundUnitRoleDropdown.setOptions( roles );
this.#groundUnitRoleDropdown.setOptions(roles);
this.clip();
}

View File

@@ -23,8 +23,7 @@ export class Slider {
if (this.#container != null) {
this.#display = this.#container.style.display;
this.#slider = <HTMLInputElement>this.#container.querySelector("input");
if (this.#slider != null)
{
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());
@@ -33,93 +32,77 @@ export class Slider {
}
}
show()
{
show() {
if (this.#container != null)
this.#container.style.display = this.#display;
}
hide()
{
hide() {
if (this.#container != null)
this.#container.style.display = 'none';
}
setActive(newActive: boolean)
{
if (this.#container && !this.#dragged)
{
setActive(newActive: boolean) {
if (this.#container && !this.#dragged) {
this.#container.classList.toggle("active", newActive);
if (!newActive && this.#valueText != null)
this.#valueText.innerText = "Mixed values";
}
}
setMinMax(newMinValue: number, newMaxValue: number)
{
setMinMax(newMinValue: number, newMaxValue: number) {
this.#minValue = newMinValue;
this.#maxValue = newMaxValue;
this.#updateMax();
}
setIncrement(newIncrement: number)
{
setIncrement(newIncrement: number) {
this.#increment = newIncrement;
this.#updateMax();
}
setValue(newValue: number)
{
setValue(newValue: number) {
// Disable value setting if the user is dragging the element
if (!this.#dragged)
{
if (!this.#dragged) {
this.#value = newValue;
if (this.#slider != null)
this.#slider.value = String((newValue - this.#minValue) / (this.#maxValue - this.#minValue) * parseFloat(this.#slider.max));
this.#slider.value = String((newValue - this.#minValue) / (this.#maxValue - this.#minValue) * parseFloat(this.#slider.max));
this.#onValue()
}
}
getValue()
{
getValue() {
return this.#value;
}
getDragged()
{
getDragged() {
return this.#dragged;
}
#updateMax()
{
#updateMax() {
var oldValue = this.getValue();
if (this.#slider != null)
this.#slider.max = String((this.#maxValue - this.#minValue) / this.#increment);
this.setValue(oldValue);
}
#onValue()
{
#onValue() {
if (this.#valueText != null && this.#slider != null)
this.#valueText.innerHTML = this.#minValue + Math.round(parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue)) + this.#unit
this.#valueText.innerHTML = this.#minValue + Math.round(parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue)) + this.#unit
this.setActive(true);
}
#onInput()
{
#onInput() {
this.#onValue();
}
#onStart()
{
#onStart() {
this.#dragged = true;
}
#onFinalize()
{
#onFinalize() {
this.#dragged = false;
if (this.#slider != null)
{
if (this.#slider != null) {
this.#value = this.#minValue + parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue);
this.#callback(this.getValue());
}

View File

@@ -1,4 +1,3 @@
import { getUnitsManager } from "..";
import { deg2rad } from "../other/utils";
import { ContextMenu } from "./contextmenu";
@@ -10,21 +9,19 @@ export class UnitContextMenu extends ContextMenu {
document.addEventListener("applyCustomFormation", () => {
var dialog = document.getElementById("custom-formation-dialog");
if (dialog)
{
if (dialog) {
dialog.classList.add("hide");
var clock = 1;
while (clock < 8)
{
if ((<HTMLInputElement> dialog.querySelector(`#formation-${clock}`)).checked)
while (clock < 8) {
if ((<HTMLInputElement>dialog.querySelector(`#formation-${clock}`)).checked)
break
clock++;
}
var angleDeg = 360 - (clock - 1) * 45;
var angleRad = deg2rad(angleDeg);
var distance = parseInt((<HTMLInputElement> dialog.querySelector(`#distance`)?.querySelector("input")).value) * 0.3048;
var upDown = parseInt((<HTMLInputElement> dialog.querySelector(`#up-down`)?.querySelector("input")).value) * 0.3048;
var distance = parseInt((<HTMLInputElement>dialog.querySelector(`#distance`)?.querySelector("input")).value) * 0.3048;
var upDown = parseInt((<HTMLInputElement>dialog.querySelector(`#up-down`)?.querySelector("input")).value) * 0.3048;
// X: front-rear, positive front
// Y: top-bottom, positive top
// Z: left-right, positive right
@@ -34,7 +31,7 @@ export class UnitContextMenu extends ContextMenu {
var z = distance * Math.sin(angleRad);
if (this.#customFormationCallback)
this.#customFormationCallback({"x": x, "y": y, "z": z})
this.#customFormationCallback({ "x": x, "y": y, "z": z })
}
})
}
@@ -43,10 +40,8 @@ export class UnitContextMenu extends ContextMenu {
this.#customFormationCallback = callback;
}
setOptions(options: {[key: string]: string}, callback: CallableFunction)
{
this.getContainer()?.replaceChildren(...Object.keys(options).map((option: string, idx: number) =>
{
setOptions(options: { [key: string]: string }, callback: CallableFunction) {
this.getContainer()?.replaceChildren(...Object.keys(options).map((option: string, idx: number) => {
var button = document.createElement("button");
button.innerHTML = options[option];
button.addEventListener("click", () => callback(option));

View File

@@ -23,13 +23,13 @@ class FeatureSwitch {
userPreference;
constructor( config:FeatureSwitchInterface ) {
constructor(config: FeatureSwitchInterface) {
this.defaultEnabled = config.defaultEnabled;
this.label = config.label;
this.masterSwitch = config.masterSwitch;
this.name = config.name;
this.onEnabled = config.onEnabled;
this.label = config.label;
this.masterSwitch = config.masterSwitch;
this.name = config.name;
this.onEnabled = config.onEnabled;
this.userPreference = this.getUserPreference();
@@ -38,16 +38,16 @@ class FeatureSwitch {
getUserPreference() {
let preferences = JSON.parse( localStorage.getItem( "featureSwitches" ) || "{}" );
let preferences = JSON.parse(localStorage.getItem("featureSwitches") || "{}");
return ( preferences.hasOwnProperty( this.name ) ) ? preferences[ this.name ] : this.defaultEnabled;
return (preferences.hasOwnProperty(this.name)) ? preferences[this.name] : this.defaultEnabled;
}
isEnabled() {
if ( !this.masterSwitch ) {
if (!this.masterSwitch) {
return false;
}
@@ -58,7 +58,7 @@ class FeatureSwitch {
export class FeatureSwitches {
#featureSwitches:FeatureSwitch[] = [
#featureSwitches: FeatureSwitch[] = [
new FeatureSwitch({
"defaultEnabled": false,
@@ -66,7 +66,7 @@ export class FeatureSwitches {
"masterSwitch": true,
"name": "aic"
}),
new FeatureSwitch({
"defaultEnabled": false,
"label": "AI Formations",
@@ -74,21 +74,21 @@ export class FeatureSwitches {
"name": "ai-formations",
"removeArtifactsIfDisabled": false
}),
new FeatureSwitch({
"defaultEnabled": false,
"label": "ATC",
"masterSwitch": true,
"name": "atc"
}),
new FeatureSwitch({
"defaultEnabled": false,
"label": "Force show unit control panel",
"masterSwitch": true,
"name": "forceShowUnitControlPanel"
}),
new FeatureSwitch({
"defaultEnabled": true,
"label": "Show splash screen",
@@ -108,41 +108,41 @@ export class FeatureSwitches {
}
getSwitch( switchName:string ) {
getSwitch(switchName: string) {
return this.#featureSwitches.find( featureSwitch => featureSwitch.name === switchName );
return this.#featureSwitches.find(featureSwitch => featureSwitch.name === switchName);
}
#testSwitches() {
for ( const featureSwitch of this.#featureSwitches ) {
if ( featureSwitch.isEnabled() ) {
if ( typeof featureSwitch.onEnabled === "function" ) {
for (const featureSwitch of this.#featureSwitches) {
if (featureSwitch.isEnabled()) {
if (typeof featureSwitch.onEnabled === "function") {
featureSwitch.onEnabled();
}
} else {
document.querySelectorAll( "[data-feature-switch='" + featureSwitch.name + "']" ).forEach( el => {
if ( featureSwitch.removeArtifactsIfDisabled === false ) {
document.querySelectorAll("[data-feature-switch='" + featureSwitch.name + "']").forEach(el => {
if (featureSwitch.removeArtifactsIfDisabled === false) {
el.remove();
} else {
el.classList.add( "hide" );
el.classList.add("hide");
}
});
}
document.body.classList.toggle( "feature-" + featureSwitch.name, featureSwitch.isEnabled() );
document.body.classList.toggle("feature-" + featureSwitch.name, featureSwitch.isEnabled());
}
}
savePreferences() {
let preferences:any = {};
let preferences: any = {};
for ( const featureSwitch of this.#featureSwitches ) {
preferences[ featureSwitch.name ] = featureSwitch.isEnabled();
for (const featureSwitch of this.#featureSwitches) {
preferences[featureSwitch.name] = featureSwitch.isEnabled();
}
localStorage.setItem( "featureSwitches", JSON.stringify( preferences ) );
localStorage.setItem("featureSwitches", JSON.stringify(preferences));
}

View File

@@ -1,9 +1,9 @@
export abstract class ToggleableFeature {
#status:boolean = false;
#status: boolean = false;
constructor( defaultStatus:boolean ) {
constructor(defaultStatus: boolean) {
this.#status = defaultStatus;
@@ -12,17 +12,17 @@ export abstract class ToggleableFeature {
}
getStatus() : boolean {
getStatus(): boolean {
return this.#status;
}
protected onStatusUpdate() {}
protected onStatusUpdate() { }
toggleStatus( force?:boolean ) : void {
toggleStatus(force?: boolean): void {
if ( force ) {
if (force) {
this.#status = force;
} else {
this.#status = !this.#status;

View File

@@ -1,10 +1,10 @@
import { Map } from 'leaflet';
import { Handler} from 'leaflet';
import { Handler } from 'leaflet';
import { Util } from 'leaflet';
import { DomUtil } from 'leaflet';
import { DomEvent } from 'leaflet';
import { LatLngBounds } from 'leaflet';
import { Bounds } from 'leaflet';
import { Bounds } from 'leaflet';
export var BoxSelect = Handler.extend({
initialize: function (map: Map) {
@@ -82,12 +82,12 @@ export var BoxSelect = Handler.extend({
this._point = this._map.mouseEventToContainerPoint(e);
var bounds = new Bounds(this._point, this._startPoint),
size = bounds.getSize();
size = bounds.getSize();
if (bounds.min != undefined)
DomUtil.setPosition(this._box, bounds.min);
this._box.style.width = size.x + 'px';
this._box.style.width = size.x + 'px';
this._box.style.height = size.y + 'px';
},
@@ -113,7 +113,7 @@ export var BoxSelect = Handler.extend({
if ((e.which !== 1) && (e.button !== 0)) { return; }
this._finish();
if (!this._moved) { return; }
// Postpone to next JS tick so internal click event handling
// still see it as "moved".
@@ -121,8 +121,8 @@ export var BoxSelect = Handler.extend({
var bounds = new LatLngBounds(
this._map.containerPointToLatLng(this._startPoint),
this._map.containerPointToLatLng(this._point));
this._map.fire('selectionend', {selectionBounds: bounds});
this._map.fire('selectionend', { selectionBounds: bounds });
},
_onKeyDown: function (e: any) {

View File

@@ -0,0 +1,12 @@
import { MiniMap, MiniMapOptions } from "leaflet-control-mini-map";
export class ClickableMiniMap extends MiniMap {
constructor(layer: L.TileLayer | L.LayerGroup, options?: MiniMapOptions) {
super(layer, options);
}
getMap() {
//@ts-ignore needed to access not exported member. A bit of a hack, required to access click events //TODO: fix me
return this._miniMap;
}
}

View File

@@ -0,0 +1,24 @@
import { Map, Marker } from "leaflet";
import { MarkerOptions } from "leaflet";
import { LatLngExpression } from "leaflet";
export class CustomMarker extends Marker {
constructor(latlng: LatLngExpression, options?: MarkerOptions) {
super(latlng, options);
}
onAdd(map: Map): this {
super.onAdd(map);
this.createIcon();
return this;
}
onRemove(map: Map): this {
super.onRemove(map);
return this;
}
createIcon() {
/* Overloaded by child classes */
}
}

View File

@@ -0,0 +1,15 @@
import { DivIcon } from "leaflet";
import { CustomMarker } from "./custommarker";
export class DestinationPreviewMarker extends CustomMarker {
createIcon() {
this.setIcon(new DivIcon({
iconSize: [52, 52],
iconAnchor: [26, 26],
className: "leaflet-destination-preview"
}));
var el = document.createElement("div");
el.classList.add("ol-destination-preview-icon");
this.getElement()?.appendChild(el);
}
}

View File

@@ -1,6 +1,4 @@
import * as L from "leaflet"
import { MiniMap, MiniMapOptions } from "leaflet-control-mini-map";
import { getUnitsManager } from "..";
import { BoxSelect } from "./boxselect";
import { MapContextMenu, SpawnOptions } from "../controls/mapcontextmenu";
@@ -10,40 +8,20 @@ import { Dropdown } from "../controls/dropdown";
import { Airbase } from "../missionhandler/airbase";
import { Unit } from "../units/unit";
import { bearing } from "../other/utils";
// TODO a bit of a hack, this module is provided as pure javascript only
require("../../node_modules/leaflet.nauticscale/dist/leaflet.nauticscale.js")
export const IDLE = "IDLE";
export const MOVE_UNIT = "MOVE_UNIT";
import { DestinationPreviewMarker } from "./destinationpreviewmarker";
import { TemporaryUnitMarker } from "./temporaryunitmarker";
import { ClickableMiniMap } from "./clickableminimap";
import { SVGInjector } from '@tanem/svg-injector'
L.Map.addInitHook('addHandler', 'boxSelect', BoxSelect);
var temporaryIcon = new L.Icon({
iconUrl: 'images/icon-temporary.png',
iconSize: [52, 52],
iconAnchor: [26, 26]
});
// TODO would be nice to convert to ts
require("../../public/javascripts/leaflet.nauticscale.js")
var destinationPreviewIcon = new L.DivIcon({
html: `<div class="ol-destination-preview-icon"></div>`,
iconSize: [52, 52],
iconAnchor: [26, 26],
className: "ol-destination-preview"
})
const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"];
export class ClickableMiniMap extends MiniMap {
constructor(layer: L.TileLayer | L.LayerGroup, options?: MiniMapOptions) {
super(layer, options);
}
getMap() {
//@ts-ignore needed to access not exported member. A bit of a hack, required to access click events
return this._miniMap;
}
}
/* Map constants */
export const IDLE = "IDLE";
export const MOVE_UNIT = "MOVE_UNIT";
export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"];
export class Map extends L.Map {
#state: string;
@@ -107,19 +85,21 @@ export class Map extends L.Map {
this.on('mousedown', (e: any) => this.#onMouseDown(e));
this.on('mouseup', (e: any) => this.#onMouseUp(e));
this.on('mousemove', (e: any) => this.#onMouseMove(e));
this.on('keydown', (e: any) => this.#updateDestinationPreview(e));
this.on('keyup', (e: any) => this.#updateDestinationPreview(e));
this.on('keydown', (e: any) => this.#updateDestinationPreview(e));
this.on('keyup', (e: any) => this.#updateDestinationPreview(e));
/* Event listeners */
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
ev.detail._element.classList.toggle("off");
document.body.toggleAttribute("data-hide-" + ev.detail.coalition);
const el = ev.detail._element;
el?.classList.toggle("off");
getUnitsManager().setHiddenType(ev.detail.coalition, (el?.currentTarget as HTMLElement)?.classList.contains("off"));
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
});
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
ev.detail._element.classList.toggle("off");
document.body.toggleAttribute("data-hide-" + ev.detail.category);
const el = ev.detail._element;
el?.classList.toggle("off");
getUnitsManager().setHiddenType(ev.detail.type, !el?.classList.contains("off"));
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
});
@@ -129,17 +109,14 @@ export class Map extends L.Map {
});
/* Pan interval */
this.#panInterval = window.setInterval(() => {
this.panBy(new L.Point( ((this.#panLeft? -1: 0) + (this.#panRight? 1: 0)) * this.#deafultPanDelta,
((this.#panUp? -1: 0) + (this.#panDown? 1: 0)) * this.#deafultPanDelta));
this.#panInterval = window.setInterval(() => {
this.panBy(new L.Point(((this.#panLeft ? -1 : 0) + (this.#panRight ? 1 : 0)) * this.#deafultPanDelta,
((this.#panUp ? -1 : 0) + (this.#panDown ? 1 : 0)) * this.#deafultPanDelta));
}, 20);
/* Option buttons */
this.#optionButtons["visibility"] = visibilityControls.map((option: string, index: number) => {
return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, "", (e: any) => {
getUnitsManager().setHiddenType(option, (e?.currentTarget as HTMLElement)?.classList.contains("off"));
(e?.currentTarget as HTMLElement)?.classList.toggle("off");
});
return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, "", "toggleUnitVisibility", `{"type": "${option}"}`);
});
document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]);
}
@@ -217,10 +194,10 @@ export class Map extends L.Map {
})
this.#destinationPreviewMarkers = [];
if (getUnitsManager().getSelectedUnits({excludeHumans: true}).length < 20) {
if (getUnitsManager().getSelectedUnits({ excludeHumans: true }).length < 20) {
/* Create the unit destination preview markers */
this.#destinationPreviewMarkers = getUnitsManager().getSelectedUnits({excludeHumans: true}).map((unit: Unit) => {
var marker = new L.Marker(this.getMouseCoordinates(), {icon: destinationPreviewIcon, interactive: false});
this.#destinationPreviewMarkers = getUnitsManager().getSelectedUnits({ excludeHumans: true }).map((unit: Unit) => {
var marker = new DestinationPreviewMarker(this.getMouseCoordinates());
marker.addTo(this);
return marker;
})
@@ -352,7 +329,7 @@ export class Map extends L.Map {
}
handleMapPanning(e: any) {
if (e.type === "keyup"){
if (e.type === "keyup") {
switch (e.code) {
case "KeyA":
case "ArrowLeft":
@@ -372,9 +349,8 @@ export class Map extends L.Map {
break;
}
}
else {
switch (e.code)
{
else {
switch (e.code) {
case 'KeyA':
case 'ArrowLeft':
this.#panLeft = true;
@@ -396,7 +372,7 @@ export class Map extends L.Map {
}
addTemporaryMarker(latlng: L.LatLng) {
var marker = new L.Marker(latlng, {icon: temporaryIcon});
var marker = new TemporaryUnitMarker(latlng);
marker.addTo(this);
this.#temporaryMarkers.push(marker);
}
@@ -413,8 +389,7 @@ export class Map extends L.Map {
i = idx;
}
});
if (closest)
{
if (closest) {
this.removeLayer(closest);
delete this.#temporaryMarkers[i];
}
@@ -449,7 +424,7 @@ export class Map extends L.Map {
if (!e.originalEvent.ctrlKey) {
getUnitsManager().selectedUnitsClearDestinations();
}
getUnitsManager().selectedUnitsAddDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null? this.#destinationRotationCenter: e.latlng, !e.originalEvent.shiftKey, this.#destinationGroupRotation)
getUnitsManager().selectedUnitsAddDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : e.latlng, !e.originalEvent.shiftKey, this.#destinationGroupRotation)
}
}
@@ -465,16 +440,14 @@ export class Map extends L.Map {
#onMouseDown(e: any) {
this.hideAllContextMenus();
if (this.#state == MOVE_UNIT && e.originalEvent.button == 2)
{
if (this.#state == MOVE_UNIT && e.originalEvent.button == 2) {
this.#computeDestinationRotation = true;
this.#destinationRotationCenter = this.getMouseCoordinates();
}
}
#onMouseUp(e: any) {
if (this.#state == MOVE_UNIT)
{
if (this.#state == MOVE_UNIT) {
this.#computeDestinationRotation = false;
this.#destinationRotationCenter = null;
this.#destinationGroupRotation = 0;
@@ -488,7 +461,7 @@ export class Map extends L.Map {
if (this.#computeDestinationRotation && this.#destinationRotationCenter != null)
this.#destinationGroupRotation = -bearing(this.#destinationRotationCenter.lat, this.#destinationRotationCenter.lng, this.getMouseCoordinates().lat, this.getMouseCoordinates().lng);
this.#updateDestinationPreview(e);
this.#updateDestinationPreview(e);
}
#onZoom(e: any) {
@@ -542,18 +515,23 @@ export class Map extends L.Map {
}
#updateDestinationPreview(e: any) {
Object.values(getUnitsManager().selectedUnitsComputeGroupDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null? this.#destinationRotationCenter: this.getMouseCoordinates(), this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => {
Object.values(getUnitsManager().selectedUnitsComputeGroupDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : this.getMouseCoordinates(), this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => {
if (idx < this.#destinationPreviewMarkers.length)
this.#destinationPreviewMarkers[idx].setLatLng(!e.originalEvent.shiftKey? latlng: this.getMouseCoordinates());
})
this.#destinationPreviewMarkers[idx].setLatLng(!e.originalEvent.shiftKey ? latlng : this.getMouseCoordinates());
})
}
#createOptionButton(value: string, url: string, title: string, callback: EventListenerOrEventListenerObject) {
#createOptionButton(value: string, url: string, title: string, callback: string, argument: string) {
var button = document.createElement("button");
const img = document.createElement("img");
img.src = `/resources/theme/images/buttons/${url}`;
img.onload = () => SVGInjector(img);
button.title = title;
button.value = value;
button.innerHTML = `<img src="/resources/theme/images/buttons/${url}" onload="SVGInject(this)" />`
button.addEventListener("click", callback);
button.appendChild(img);
button.setAttribute("data-on-click", callback);
button.setAttribute("data-on-click-params", argument);
return button;
}
}

View File

@@ -0,0 +1,13 @@
import { Icon } from "leaflet";
import { CustomMarker } from "./custommarker";
export class TemporaryUnitMarker extends CustomMarker {
createIcon() {
var icon = new Icon({
iconUrl: '/resources/theme/images/markers/temporary-icon.png',
iconSize: [52, 52],
iconAnchor: [26, 26]
});
this.setIcon(icon);
}
}

View File

@@ -1,13 +1,14 @@
import * as L from 'leaflet'
import { DivIcon } from 'leaflet';
import { CustomMarker } from '../map/custommarker';
import { SVGInjector } from '@tanem/svg-injector';
export interface AirbaseOptions
{
name: string,
position: L.LatLng,
src: string
position: L.LatLng
}
export class Airbase extends L.Marker
export class Airbase extends CustomMarker
{
#name: string = "";
#coalition: string = "";
@@ -19,21 +20,30 @@ export class Airbase extends L.Marker
super(options.position, { riseOnHover: true });
this.#name = options.name;
var icon = new L.DivIcon({
html: ` <div class="airbase" data-object="airbase" data-coalition="neutral">
<div class="airbase-marker"> </div>
</div>`,
}
createIcon() {
var icon = new DivIcon({
className: 'leaflet-airbase-marker',
iconSize: [40, 40],
iconAnchor: [20, 20]
}); // Set the marker, className must be set to avoid white square
this.setIcon(icon);
var el = document.createElement("div");
el.classList.add("airbase-icon");
el.setAttribute("data-object", "airbase");
var img = document.createElement("img");
img.src = "/resources/theme/images/markers/airbase.svg";
img.onload = () => SVGInjector(img);
el.appendChild(img);
this.getElement()?.appendChild(el);
}
setCoalition(coalition: string)
{
this.#coalition = coalition;
(<HTMLElement> this.getElement()?.querySelector(".airbase")).dataset.coalition = this.#coalition;
(<HTMLElement> this.getElement()?.querySelector(".airbase-icon")).dataset.coalition = this.#coalition;
}
getCoalition()

View File

@@ -0,0 +1,36 @@
import { DivIcon } from "leaflet";
import { CustomMarker } from "../map/custommarker";
import { SVGInjector } from "@tanem/svg-injector";
export class Bullseye extends CustomMarker {
#coalition: string = "";
createIcon() {
var icon = new DivIcon({
className: 'leaflet-bullseye-marker',
iconSize: [40, 40],
iconAnchor: [20, 20]
}); // Set the marker, className must be set to avoid white square
this.setIcon(icon);
var el = document.createElement("div");
el.classList.add("bullseye-icon");
el.setAttribute("data-object", "bullseye");
var img = document.createElement("img");
img.src = "/resources/theme/images/markers/bullseye.svg";
img.onload = () => SVGInjector(img);
el.appendChild(img);
this.getElement()?.appendChild(el);
}
setCoalition(coalition: string)
{
this.#coalition = coalition;
(<HTMLElement> this.getElement()?.querySelector(".bullseye-icon")).dataset.coalition = this.#coalition;
}
getCoalition()
{
return this.#coalition;
}
}

View File

@@ -1,44 +1,58 @@
import { Marker, LatLng, Icon } from "leaflet";
import { LatLng } from "leaflet";
import { getInfoPopup, getMap } from "..";
import { Airbase } from "./airbase";
var bullseyeIcons = [
new Icon({ iconUrl: 'images/bullseye0.png', iconAnchor: [30, 30]}),
new Icon({ iconUrl: 'images/bullseye1.png', iconAnchor: [30, 30]}),
new Icon({ iconUrl: 'images/bullseye2.png', iconAnchor: [30, 30]})
]
import { Bullseye } from "./bullseye";
export class MissionHandler
{
#bullseyes : any; //TODO declare interface
#bullseyeMarkers: any;
#airbases : any; //TODO declare interface
#airbasesMarkers: {[name: string]: Airbase};
#bullseyes : {[name: string]: Bullseye} = {};
#airbases : {[name: string]: Airbase} = {};
#theatre : string = "";
constructor()
{
this.#bullseyes = undefined;
this.#bullseyeMarkers = [
new Marker([0, 0], {icon: bullseyeIcons[0]}).addTo(getMap()),
new Marker([0, 0], {icon: bullseyeIcons[1]}).addTo(getMap()),
new Marker([0, 0], {icon: bullseyeIcons[2]}).addTo(getMap())
]
this.#airbasesMarkers = {};
}
update(data: BullseyesData | AirbasesData | any)
{
if ("bullseyes" in data)
{
this.#bullseyes = data.bullseyes;
this.#drawBullseyes();
for (let idx in data.bullseyes)
{
const bullseye = data.bullseyes[idx];
if (!(idx in this.#bullseyes))
this.#bullseyes[idx] = new Bullseye([0, 0]).addTo(getMap());
if (bullseye.latitude && bullseye.longitude && bullseye.coalition)
{
this.#bullseyes[idx].setLatLng(new LatLng(bullseye.latitude, bullseye.longitude));
this.#bullseyes[idx].setCoalition(bullseye.coalition);
}
}
}
if ("airbases" in data)
{
this.#airbases = data.airbases;
this.#drawAirbases();
for (let idx in data.airbases)
{
var airbase = data.airbases[idx]
if (this.#airbases[idx] === undefined)
{
this.#airbases[idx] = new Airbase({
position: new LatLng(airbase.latitude, airbase.longitude),
name: airbase.callsign
}).addTo(getMap());
this.#airbases[idx].on('contextmenu', (e) => this.#onAirbaseClick(e));
}
if (airbase.latitude && airbase.longitude && airbase.coalition)
{
this.#airbases[idx].setLatLng(new LatLng(airbase.latitude, airbase.longitude));
this.#airbases[idx].setCoalition(airbase.coalition);
}
//this.#airbases[idx].setProperties(["Runway 1: 31L / 13R", "Runway 2: 31R / 13L", "TCN: 17X", "ILS: ---" ]);
//this.#airbases[idx].setParkings(["2x big", "5x small"]);
}
}
if ("mission" in data)
@@ -58,38 +72,6 @@ export class MissionHandler
return this.#bullseyes;
}
#drawBullseyes()
{
for (let idx in this.#bullseyes)
{
var bullseye = this.#bullseyes[idx];
this.#bullseyeMarkers[idx].setLatLng(new LatLng(bullseye.latitude, bullseye.longitude));
}
}
#drawAirbases()
{
for (let idx in this.#airbases)
{
var airbase = this.#airbases[idx]
if (this.#airbasesMarkers[idx] === undefined)
{
this.#airbasesMarkers[idx] = new Airbase({
position: new LatLng(airbase.latitude, airbase.longitude),
name: airbase.callsign,
src: "images/airbase.png"}).addTo(getMap());
this.#airbasesMarkers[idx].on('contextmenu', (e) => this.#onAirbaseClick(e));
}
else
{
this.#airbasesMarkers[idx].setLatLng(new LatLng(airbase.latitude, airbase.longitude));
this.#airbasesMarkers[idx].setCoalition(airbase.coalition);
//this.#airbasesMarkers[idx].setProperties(["Runway 1: 31L / 13R", "Runway 2: 31R / 13L", "TCN: 17X", "ILS: ---" ]);
//this.#airbasesMarkers[idx].setParkings(["2x big", "5x small"]);
}
}
}
#onAirbaseClick(e: any)
{
getMap().showAirbaseContextMenu(e, e.sourceTarget);

View File

@@ -154,4 +154,10 @@ export function mercatorToLatLng(x: number, y: number) {
lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180.0)) - Math.PI / 2.0);
return { lng: lng, lat: lat };
}
export function createDivWithClass(className: string) {
var el = document.createElement("div");
el.classList.add(className);
return el;
}

View File

@@ -37,8 +37,8 @@ export class MouseInfoPanel extends Panel {
if ( el != null ) {
var dist = distance(bullseyes[idx].latitude, bullseyes[idx].longitude, mousePosition.lat, mousePosition.lng);
var bear = bearing(bullseyes[idx].latitude, bullseyes[idx].longitude, mousePosition.lat, mousePosition.lng);
var dist = distance(bullseyes[idx].getLatLng().lat, bullseyes[idx].getLatLng().lng, mousePosition.lat, mousePosition.lng);
var bear = bearing(bullseyes[idx].getLatLng().lat, bullseyes[idx].getLatLng().lng, mousePosition.lat, mousePosition.lng);
let bng = zeroAppend(Math.floor(bear), 3);

View File

@@ -346,7 +346,7 @@ export class UnitControlPanel extends Panel {
var button = document.createElement("button");
button.title = title;
button.value = value;
button.innerHTML = `<img src="/resources/theme/images/buttons/${url}" onload="SVGInject(this)" />`
button.innerHTML = `<img src="/resources/theme/images/buttons/${url}" />`
button.addEventListener("click", callback);
return button;
}

View File

@@ -4,14 +4,16 @@ import { rad2deg } from '../other/utils';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures } from '../server/server';
import { aircraftDatabase } from './aircraftdatabase';
import { groundUnitsDatabase } from './groundunitsdatabase';
import { CustomMarker } from '../map/custommarker';
import { SVGInjector } from '@tanem/svg-injector';
var pathIcon = new Icon({
iconUrl: 'images/marker-icon.png',
shadowUrl: 'images/marker-shadow.png',
iconUrl: '/resources/theme/images/markers/marker-icon.png',
shadowUrl: '/resources/theme/images/markers/marker-shadow.png',
iconAnchor: [13, 41]
});
export class Unit extends Marker {
export class Unit extends CustomMarker {
ID: number;
#data: UnitData = {
@@ -114,22 +116,7 @@ export class Unit extends Marker {
/* Set the unit data */
this.setData(data);
/* Set the icon */
var icon = new DivIcon({
html: this.getMarkerHTML(),
className: 'leaflet-unit-marker',
iconAnchor: [25, 25],
iconSize: [50, 50],
});
this.setIcon(icon);
}
getMarkerHTML() {
return `<div class="unit" data-object="unit-${this.getMarkerCategory()}" data-coalition="${this.getMissionData().coalition}">
<div class="unit-selected-spotlight"></div>
<div class="unit-marker"><img src="/resources/theme/images/units/${this.getMarkerCategory()}.svg" onload="SVGInject(this)"/></div>
<div class="unit-short-label"></div>
</div>`
}
getMarkerCategory() {
@@ -137,6 +124,20 @@ export class Unit extends Marker {
return "";
}
getActiveMarkerElements() {
// Default values
return {
state: false,
vvi: false,
hotgroup: false,
unitIcon: true,
shortLabel: false,
fuel: false,
ammo: false,
summary: false
}
}
setSelected(selected: boolean) {
/* Only alive units can be selected. Some units are not selectable (weapons) */
if ((this.getBaseData().alive || !selected) && this.getSelectable() && this.getSelected() != selected) {
@@ -285,6 +286,104 @@ export class Unit extends Marker {
return this.getData().optionsData;
}
/********************** Icon *************************/
createIcon(): void {
/* Set the icon */
var icon = new DivIcon({
className: 'leaflet-unit-icon',
iconAnchor: [25, 25],
iconSize: [50, 50],
});
this.setIcon(icon);
var el = document.createElement("div");
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
el.setAttribute("data-coalition", this.getMissionData().coalition);
// Generate and append elements depending on active options
// State icon
if (this.getActiveMarkerElements().state){
var state = document.createElement("div");
state.classList.add("unit-state");
el.appendChild(state);
}
// Velocity vector
if (this.getActiveMarkerElements().vvi) {
var vvi = document.createElement("div");
vvi.classList.add("unit-vvi");
vvi.toggleAttribute("data-rotate-to-heading");
el.append(vvi);
}
// Hotgroup indicator
if (this.getActiveMarkerElements().hotgroup) {
var hotgroup = document.createElement("div");
hotgroup.classList.add("unit-hotgroup");
var hotgroupId = document.createElement("div");
hotgroupId.classList.add("unit-hotgroup-id");
hotgroup.appendChild(hotgroupId);
el.append(hotgroup);
}
// Main icon
if (this.getActiveMarkerElements().unitIcon) {
var unitIcon = document.createElement("div");
unitIcon.classList.add("unit-icon");
var img = document.createElement("img");
img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`;
img.onload = () => SVGInjector(img);
unitIcon.appendChild(img);
el.append(unitIcon);
}
// Short label
if (this.getActiveMarkerElements().shortLabel) {
var shortLabel = document.createElement("div");
shortLabel.classList.add("unit-short-label");
shortLabel.innerText = aircraftDatabase.getByName(this.getBaseData().name)?.shortLabel || ""; //TODO: fix, use correct database
el.append(shortLabel);
}
// Fuel indicator
if (this.getActiveMarkerElements().fuel) {
var fuelIndicator = document.createElement("div");
fuelIndicator.classList.add("unit-fuel");
var fuelLevel = document.createElement("div");
fuelLevel.classList.add("unit-fuel-level");
fuelIndicator.appendChild(fuelLevel);
el.append(fuelIndicator);
}
// Ammo indicator
if (this.getActiveMarkerElements().ammo){
var ammoIndicator = document.createElement("div");
ammoIndicator.classList.add("unit-ammo");
for (let i = 0; i <= 3; i++)
ammoIndicator.appendChild(document.createElement("div"));
el.append(ammoIndicator);
}
// Unit summary
if (this.getActiveMarkerElements().summary) {
var summary = document.createElement("div");
summary.classList.add("unit-summary");
var callsign = document.createElement("div");
callsign.classList.add("unit-callsign");
callsign.innerText = this.getBaseData().unitName;
var altitude = document.createElement("div");
altitude.classList.add("unit-altitude");
var speed = document.createElement("div");
speed.classList.add("unit-speed");
summary.appendChild(callsign);
summary.appendChild(altitude);
summary.appendChild(speed);
el.appendChild(summary);
}
this.getElement()?.appendChild(el);
}
/********************** Visibility *************************/
updateVisibility() {
var hidden = false;
@@ -295,7 +394,9 @@ export class Unit extends Marker {
hidden = true;
else if (hiddenUnits.includes(this.getMarkerCategory()))
hidden = true;
this.setHidden(document.body.getAttribute(`data-hide-${this.getMissionData().coalition}`) != null || hidden || !this.getBaseData().alive);
else if (hiddenUnits.includes(this.getMissionData().coalition))
hidden = true;
this.setHidden(hidden || !this.getBaseData().alive);
}
setHidden(hidden: boolean) {
@@ -576,7 +677,7 @@ export class Unit extends Marker {
el.setAttribute("style", currentStyle + `transform:rotate(${headingDeg}deg);`);
});
/* Turn on ordnance indicators */
/* Turn on ammo indicators */
var hasFox1 = element.querySelector(".unit")?.hasAttribute("data-has-fox-1");
var hasFox2 = element.querySelector(".unit")?.hasAttribute("data-has-fox-2");
var hasFox3 = element.querySelector(".unit")?.hasAttribute("data-has-fox-3");
@@ -690,7 +791,18 @@ export class Unit extends Marker {
}
export class AirUnit extends Unit {
getActiveMarkerElements() {
return {
state: true,
vvi: true,
hotgroup: true,
unitIcon: true,
shortLabel: true,
fuel: true,
ammo: true,
summary: true
};
}
}
export class Aircraft extends AirUnit {
@@ -698,30 +810,6 @@ export class Aircraft extends AirUnit {
super(ID, data);
}
getMarkerHTML() {
return `<div class="unit" data-object="unit-aircraft" data-coalition="${this.getMissionData().coalition}">
<div class="unit-state"></div>
<div class="unit-vvi" data-rotate-to-heading></div>
<div class="unit-hotgroup"><div class="unit-hotgroup-id"></div></div>
<div class="unit-marker"><img src="/resources/theme/images/units/aircraft.svg" onload="SVGInject(this)"/></div>
<div class="unit-short-label">${aircraftDatabase.getByName(this.getBaseData().name)?.shortLabel || ""}</div>
<div class="unit-fuel">
<div class="unit-fuel-level" style="width:100%;"></div>
</div>
<div class="unit-ammo">
<div class="unit-ammo-fox-1"></div>
<div class="unit-ammo-fox-2"></div>
<div class="unit-ammo-fox-3"></div>
<div class="unit-ammo-other"></div>
</div>
<div class="unit-summary">
<div class="unit-callsign">${this.getBaseData().unitName}</div>
<div class="unit-altitude"></div>
<div class="unit-speed"></div>
</div>
</div>`
}
getMarkerCategory() {
return "aircraft";
}
@@ -732,7 +820,7 @@ export class Helicopter extends AirUnit {
super(ID, data);
}
getVisibilityCategory() {
getMarkerCategory() {
return "helicopter";
}
}
@@ -742,15 +830,17 @@ export class GroundUnit extends Unit {
super(ID, data);
}
getMarkerHTML() {
var role = groundUnitsDatabase.getByName(this.getBaseData().name)?.loadouts[0].roles[0];
return `<div class="unit" data-object="unit-${this.getMarkerCategory()}" data-coalition="${this.getMissionData().coalition}">
<div class="unit-marker"><img src="/resources/theme/images/units/${this.getMarkerCategory()}.svg" onload="SVGInject(this)"/></div>
<div class="unit-short-label">${role?.substring(0, 1)?.toUpperCase() || ""}</div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id"></div>
</div>
</div>`
getActiveMarkerElements() {
return {
state: true,
vvi: false,
hotgroup: true,
unitIcon: true,
shortLabel: true,
fuel: false,
ammo: false,
summary: false
};
}
getMarkerCategory() {
@@ -766,6 +856,19 @@ export class NavyUnit extends Unit {
super(ID, data);
}
getActiveMarkerElements() {
return {
state: true,
vvi: false,
hotgroup: true,
unitIcon: true,
shortLabel: true,
fuel: false,
ammo: false,
summary: false
};
}
getMarkerCategory() {
return "navyunit";
}
@@ -776,14 +879,6 @@ export class Weapon extends Unit {
super(ID, data);
this.setSelectable(false);
}
getMarkerHTML(): string {
return `<div class="unit" data-object="unit-${this.getMarkerCategory()}" data-coalition="${this.getMissionData().coalition}">
<div class="unit-marker" data-rotate-to-heading><img src="/resources/theme/images/units/${this.getMarkerCategory()}.svg" onload="SVGInject(this)"/></div>
<div class="unit-short-label"></div>
</div>`
}
}
export class Missile extends Weapon {