diff --git a/frontend/react/src/constants/constants.ts b/frontend/react/src/constants/constants.ts
index 486fdc30..1f556893 100644
--- a/frontend/react/src/constants/constants.ts
+++ b/frontend/react/src/constants/constants.ts
@@ -259,7 +259,8 @@ export const defaultMapLayers = {};
export const IDLE = "Idle";
export const SPAWN_UNIT = "Spawn unit";
export const CONTEXT_ACTION = "Context action";
-export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area";
+export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area polygon";
+export const COALITIONAREA_EDIT = "Edit Coalition Area";
export const IADSTypes = ["AAA", "SAM Site", "Radar (EWR)"];
export const IADSDensities: { [key: string]: number } = {
diff --git a/frontend/react/src/map/coalitionarea/coalitionarea.ts b/frontend/react/src/map/coalitionarea/coalitionarea.ts
index a9b7423c..4d20bfdd 100644
--- a/frontend/react/src/map/coalitionarea/coalitionarea.ts
+++ b/frontend/react/src/map/coalitionarea/coalitionarea.ts
@@ -31,7 +31,6 @@ export class CoalitionArea extends Polygon {
super(latlngs, options);
this.#setColors();
- this.#registerCallbacks();
if (
[BLUE_COMMANDER, RED_COMMANDER].includes(
@@ -175,20 +174,4 @@ export class CoalitionArea extends Polygon {
});
}
}
-
- #registerCallbacks() {
- this.on("click", (e: any) => {
- getApp().getMap().deselectAllCoalitionAreas();
- if (!this.getSelected()) {
- this.setSelected(true);
- }
- });
-
- this.on("contextmenu", (e: any) => {
- if (!this.getEditing()) {
- getApp().getMap().deselectAllCoalitionAreas();
- this.setSelected(true);
- } else this.setEditing(false);
- });
- }
}
diff --git a/frontend/react/src/map/dcslayer.ts b/frontend/react/src/map/dcslayer.ts
deleted file mode 100644
index 5b3d6d92..00000000
--- a/frontend/react/src/map/dcslayer.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import * as L from "leaflet";
-
-export class DCSLayer extends L.TileLayer {
- createTile(coords: L.Coords, done: L.DoneCallback) {
- let newDone = (error?: Error, tile?: HTMLElement) => {
- if (
- error === null &&
- tile !== undefined &&
- !tile.classList.contains("filtered")
- ) {
- // Create a canvas and set its width and height.
- var canvas = document.createElement("canvas");
- canvas.setAttribute("width", "256px");
- canvas.setAttribute("height", "256px");
-
- // Get the canvas drawing context, and draw the image to it.
- var context = canvas.getContext("2d");
- if (context) {
- context.drawImage(
- tile as CanvasImageSource,
- 0,
- 0,
- canvas.width,
- canvas.height
- );
-
- // Get the canvas image data.
- var imageData = context.getImageData(
- 0,
- 0,
- canvas.width,
- canvas.height
- );
-
- // Create a function for preserving a specified colour.
- var makeTransparent = function (
- imageData: ImageData,
- color: { r: number; g: number; b: number }
- ) {
- // Get the pixel data from the source.
- var data = imageData.data;
- // Iterate through all the pixels.
- for (var i = 0; i < data.length; i += 4) {
- // Check if the current pixel should have preserved transparency. This simply compares whether the color we passed in is equivalent to our pixel data.
- var convert =
- data[i] > color.r - 5 &&
- data[i] < color.r + 5 &&
- data[i + 1] > color.g - 5 &&
- data[i + 1] < color.g + 5 &&
- data[i + 2] > color.b - 5 &&
- data[i + 2] < color.b + 5;
-
- // Either preserve the initial transparency or set the transparency to 0.
- data[i + 3] = convert ? 100 : data[i + 3];
- }
- return imageData;
- };
-
- // Get the new pixel data and set it to the canvas context.
- var newData = makeTransparent(imageData, { r: 26, g: 109, b: 127 });
- context.putImageData(newData, 0, 0);
- (tile as HTMLImageElement).src = canvas.toDataURL();
- tile.classList.add("filtered");
- }
- } else {
- return done(error, tile);
- }
- };
- return super.createTile(coords, newDone);
- }
-}
diff --git a/frontend/react/src/map/theme.css b/frontend/react/src/map/map.css
similarity index 87%
rename from frontend/react/src/map/theme.css
rename to frontend/react/src/map/map.css
index 744e3347..fd06d5c4 100644
--- a/frontend/react/src/map/theme.css
+++ b/frontend/react/src/map/map.css
@@ -97,3 +97,24 @@
* {
font-weight: 600;
}
+
+.ol-coalitionarea-handle-icon {
+ background-color: #FFFFFFAA;
+ width: 100%;
+ height: 100%;
+ border-radius: 999px;
+}
+
+.ol-coalitionarea-handle-icon {
+ background-color: #FFFFFFAA;
+ width: 100%;
+ height: 100%;
+ border-radius: 999px;
+}
+
+.ol-coalitionarea-middle-handle-icon {
+ background-color: #FFFFFFAA;
+ width: 100%;
+ height: 100%;
+ border-radius: 999px;
+}
\ No newline at end of file
diff --git a/frontend/react/src/map/map.ts b/frontend/react/src/map/map.ts
index 3d115636..4db0e406 100644
--- a/frontend/react/src/map/map.ts
+++ b/frontend/react/src/map/map.ts
@@ -3,13 +3,7 @@ import { getApp } from "../olympusapp";
import { BoxSelect } from "./boxselect";
import { Airbase } from "../mission/airbase";
import { Unit } from "../unit/unit";
-import {
- bearing,
- deg2rad,
- getGroundElevation,
- polyContains,
-} from "../other/utils";
-import { DestinationPreviewMarker } from "./markers/destinationpreviewmarker";
+import { deg2rad, getGroundElevation, polyContains } from "../other/utils";
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
import { ClickableMiniMap } from "./clickableminimap";
import {
@@ -23,21 +17,19 @@ import {
CONTEXT_ACTION,
MAP_OPTIONS_DEFAULTS,
MAP_HIDDEN_TYPES_DEFAULTS,
+ COALITIONAREA_EDIT,
} from "../constants/constants";
import { CoalitionArea } from "./coalitionarea/coalitionarea";
-import { TouchBoxSelect } from "./touchboxselect";
-import { DestinationPreviewHandle } from "./markers/destinationpreviewHandle";
-
-import "./markers/stylesheets/airbase.css";
-import "./markers/stylesheets/bullseye.css";
-import "./markers/stylesheets/units.css";
-
-// Temporary
-import "./theme.css";
import { MapHiddenTypes, MapOptions } from "../types/types";
import { SpawnRequestTable } from "../interfaces";
import { ContextAction } from "../unit/contextaction";
+/* Stylesheets */
+import "./markers/stylesheets/airbase.css";
+import "./markers/stylesheets/bullseye.css";
+import "./markers/stylesheets/units.css";
+import "./map.css";
+
L.Map.addInitHook("addHandler", "boxSelect", BoxSelect);
export class Map extends L.Map {
@@ -45,58 +37,68 @@ export class Map extends L.Map {
#options: MapOptions = MAP_OPTIONS_DEFAULTS;
#hiddenTypes: MapHiddenTypes = MAP_HIDDEN_TYPES_DEFAULTS;
- #ID: string;
+ /* State machine */
#state: string;
+
+ /* Map layers */
+ #theatre: string = "";
#layer: L.TileLayer | L.LayerGroup | null = null;
+ #layerName: string = "";
+ #mapLayers: any = defaultMapLayers;
+ #mapMirrors: any = defaultMapMirrors;
- #spawnRequestTable: SpawnRequestTable | null = null;
+ /* Inputs timers */
+ #mouseCooldownTimer: number = 0;
+ #shortPressTimer: number = 0;
+ #longPressTimer: number = 0;
- #preventLeftClick: boolean = false;
- #leftClickTimer: number = 0;
- #deafultPanDelta: number = 100;
+ /* Camera keyboard panning control */
+ defaultPanDelta: number = 100;
#panInterval: number | null = null;
#panLeft: boolean = false;
#panRight: boolean = false;
#panUp: boolean = false;
#panDown: boolean = false;
- #lastMousePosition: L.Point = new L.Point(0, 0);
- #lastMouseCoordinates: L.LatLng = new L.LatLng(0, 0);
+ /* Keyboard state */
+ #isShiftKeyDown: boolean = false;
- #shiftKey: boolean = false;
- #centerUnit: Unit | null = null;
+ /* Center on unit target */
+ #centeredUnit: Unit | null = null;
+ /* Minimap */
#miniMap: ClickableMiniMap | null = null;
#miniMapLayerGroup: L.LayerGroup;
#miniMapPolyline: L.Polyline;
- #temporaryMarkers: TemporaryUnitMarker[] = [];
-
- #isSelecting: boolean = false;
+ /* Other state controls */
+ #isMouseOnCooldown: boolean = false;
#isZooming: boolean = false;
+ #isDragging: boolean = false;
+ #isMouseDown: boolean = false;
+ #lastMousePosition: L.Point = new L.Point(0, 0);
+ #lastMouseCoordinates: L.LatLng = new L.LatLng(0, 0);
#previousZoom: number = 0;
+ /* Camera control plugin */
#slaveDCSCamera: boolean = false;
#slaveDCSCameraAvailable: boolean = false;
#cameraControlTimer: number = 0;
#cameraControlPort: number = 3003;
#cameraControlMode: string = "map";
-
- #coalitionAreas: CoalitionArea[] = [];
-
- #mapLayers: any = defaultMapLayers;
- #mapMirrors: any = defaultMapMirrors;
- #layerName: string = "";
#cameraOptionsXmlHttp: XMLHttpRequest | null = null;
#bradcastPositionXmlHttp: XMLHttpRequest | null = null;
#cameraZoomRatio: number = 1.0;
+ /* Coalition areas drawing */
+ #coalitionAreas: CoalitionArea[] = [];
+
+ /* Unit context actions */
#contextAction: null | ContextAction = null;
- #theatre: string = "";
- #waitingForDoubleClick: boolean = false;
- #doubleClickTimer: number = 0;
- #longPressTimer: number = 0;
- #isDragging: boolean = false;
+
+ /* Unit spawning */
+ #spawnRequestTable: SpawnRequestTable | null = null;
+ #temporaryMarkers: TemporaryUnitMarker[] = [];
/**
*
@@ -119,8 +121,6 @@ export class Map extends L.Map {
});
this.setView([37.23, -115.8], 10);
- this.#ID = ID;
-
/* Minimap */
var minimapLayer = new L.TileLayer(
"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
@@ -134,24 +134,28 @@ export class Map extends L.Map {
this.#state = IDLE;
/* Register event handles */
- this.on("click", (e: any) => this.#onClick(e));
- this.on("dblclick", (e: any) => this.#onDoubleClick(e));
this.on("zoomstart", (e: any) => this.#onZoomStart(e));
this.on("zoom", (e: any) => this.#onZoom(e));
this.on("zoomend", (e: any) => this.#onZoomEnd(e));
- this.on("drag", (e: any) => this.centerOnUnit(null));
+
this.on("dragstart", (e: any) => this.#onDragStart(e));
+ this.on("drag", (e: any) => this.centerOnUnit(null));
this.on("dragend", (e: any) => this.#onDragEnd(e));
- this.on("contextmenu", (e: any) => this.#onContextMenu(e));
+
this.on("selectionstart", (e: any) => this.#onSelectionStart(e));
this.on("selectionend", (e: any) => this.#onSelectionEnd(e));
+
+ this.on("dblclick", (e: any) => this.#onDoubleClick(e));
this.on("mouseup", (e: any) => this.#onMouseUp(e));
this.on("mousedown", (e: any) => this.#onMouseDown(e));
+
this.on("mousemove", (e: any) => this.#onMouseMove(e));
+
this.on("keydown", (e: any) => this.#onKeyDown(e));
this.on("keyup", (e: any) => this.#onKeyUp(e));
+
this.on("move", (e: any) => {
- if (this.#slaveDCSCamera) this.#broadcastPosition();
+ this.#onMapMove(e);
});
L.DomEvent.on(this.getContainer(), "touchstart", this.#onMouseDown, this);
@@ -259,11 +263,11 @@ export class Map extends L.Map {
this.panBy(
new L.Point(
((this.#panLeft ? -1 : 0) + (this.#panRight ? 1 : 0)) *
- this.#deafultPanDelta *
- (this.#shiftKey ? 3 : 1),
+ this.defaultPanDelta *
+ (this.#isShiftKeyDown ? 3 : 1),
((this.#panUp ? -1 : 0) + (this.#panDown ? 1 : 0)) *
- this.#deafultPanDelta *
- (this.#shiftKey ? 3 : 1)
+ this.defaultPanDelta *
+ (this.#isShiftKeyDown ? 3 : 1)
)
);
}, 20);
@@ -368,6 +372,9 @@ export class Map extends L.Map {
/* Operations to perform if you are NOT in a state */
if (this.#state !== COALITIONAREA_DRAW_POLYGON) {
+ this.getSelectedCoalitionArea()?.setEditing(false);
+ }
+ if (this.#state !== COALITIONAREA_EDIT) {
this.#deselectSelectedCoalitionArea();
}
@@ -416,104 +423,6 @@ export class Map extends L.Map {
return this.#hiddenTypes;
}
- /* Context Menus */
- hideAllContextMenus() {
- this.hideMapContextMenu();
- this.hideUnitContextMenu();
- this.hideAirbaseContextMenu();
- this.hideAirbaseSpawnMenu();
- this.hideCoalitionAreaContextMenu();
- }
-
- showMapContextMenu(x: number, y: number, latlng: L.LatLng) {
- //this.hideAllContextMenus();
- //this.#mapContextMenu.show(x, y, latlng);
- //document.dispatchEvent(new CustomEvent("mapContextMenu"));
- }
-
- hideMapContextMenu() {
- //this.#mapContextMenu.hide();
- //document.dispatchEvent(new CustomEvent("mapContextMenu"));
- }
-
- getMapContextMenu() {
- return null; //this.#mapContextMenu;
- }
-
- showUnitContextMenu(
- x: number | undefined = undefined,
- y: number | undefined = undefined,
- latlng: L.LatLng | undefined = undefined
- ) {
- //this.hideAllContextMenus();
- //this.#unitContextMenu.show(x, y, latlng);
- }
-
- getUnitContextMenu() {
- return null; //this.#unitContextMenu;
- }
-
- hideUnitContextMenu() {
- //this.#unitContextMenu.hide();
- }
-
- showAirbaseContextMenu(
- airbase: Airbase,
- x: number | undefined = undefined,
- y: number | undefined = undefined,
- latlng: L.LatLng | undefined = undefined
- ) {
- //this.hideAllContextMenus();
- //this.#airbaseContextMenu.show(x, y, latlng);
- //this.#airbaseContextMenu.setAirbase(airbase);
- }
-
- getAirbaseContextMenu() {
- return null; //this.#airbaseContextMenu;
- }
-
- hideAirbaseContextMenu() {
- //this.#airbaseContextMenu.hide();
- }
-
- showAirbaseSpawnMenu(
- airbase: Airbase,
- x: number | undefined = undefined,
- y: number | undefined = undefined,
- latlng: L.LatLng | undefined = undefined
- ) {
- //this.hideAllContextMenus();
- //this.#airbaseSpawnMenu.show(x, y);
- //this.#airbaseSpawnMenu.setAirbase(airbase);
- }
-
- getAirbaseSpawnMenu() {
- return null; //this.#airbaseSpawnMenu;
- }
-
- hideAirbaseSpawnMenu() {
- //this.#airbaseSpawnMenu.hide();
- }
-
- showCoalitionAreaContextMenu(
- x: number,
- y: number,
- latlng: L.LatLng,
- coalitionArea: CoalitionArea
- ) {
- //this.hideAllContextMenus();
- //this.#coalitionAreaContextMenu.show(x, y, latlng);
- //this.#coalitionAreaContextMenu.setCoalitionArea(coalitionArea);
- }
-
- getCoalitionAreaContextMenu() {
- return null; //this.#coalitionAreaContextMenu;
- }
-
- hideCoalitionAreaContextMenu() {
- //this.#coalitionAreaContextMenu.hide();
- }
-
getMousePosition() {
return this.#lastMousePosition;
}
@@ -525,15 +434,15 @@ export class Map extends L.Map {
centerOnUnit(unit: Unit | null) {
if (unit !== null) {
this.options.scrollWheelZoom = "center";
- this.#centerUnit = unit;
+ this.#centeredUnit = unit;
} else {
this.options.scrollWheelZoom = undefined;
- this.#centerUnit = null;
+ this.#centeredUnit = null;
}
}
getCenteredOnUnit() {
- return this.#centerUnit;
+ return this.#centeredUnit;
}
setTheatre(theatre: string) {
@@ -688,10 +597,6 @@ export class Map extends L.Map {
return false;
}
- getMapMarkerVisibilityControls() {
- return null; //this.#mapMarkerVisibilityControls;
- }
-
setSlaveDCSCamera(newSlaveDCSCamera: boolean) {
this.#slaveDCSCamera = newSlaveDCSCamera;
let button = document.getElementById("camera-link-control");
@@ -740,75 +645,6 @@ export class Map extends L.Map {
}
/* Event handlers */
- #onClick(e: any) {
- /* Exit if we were waiting for a doubleclick */
- if (this.#waitingForDoubleClick) {
- return;
- }
-
- /* We'll wait for a doubleclick */
- this.#waitingForDoubleClick = true;
-
- this.#doubleClickTimer = window.setTimeout(() => {
- /* Still waiting so no doubleclick; do the click action */
- if (this.#waitingForDoubleClick) {
- if (!this.#preventLeftClick) {
- /* Execute the short click action */
- if (this.#state === IDLE) {
- this.deselectAllCoalitionAreas();
- } else if (this.#state === SPAWN_UNIT) {
- if (this.#spawnRequestTable !== null) {
- const location = e.latlng;
- this.#spawnRequestTable.unit.location = e.latlng;
- getApp()
- .getUnitsManager()
- .spawnUnits(
- this.#spawnRequestTable.category,
- [this.#spawnRequestTable.unit],
- this.#spawnRequestTable.coalition,
- false,
- undefined,
- undefined,
- (hash) => {
- this.addTemporaryMarker(
- location,
- this.#spawnRequestTable?.unit.unitType ?? "unknown",
- this.#spawnRequestTable?.coalition ?? "blue",
- hash
- );
- }
- );
- }
- } else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
- if (this.getSelectedCoalitionArea()?.getEditing()) {
- this.getSelectedCoalitionArea()?.addTemporaryLatLng(e.latlng);
- } else {
- this.deselectAllCoalitionAreas();
- }
- } else if (this.#state === CONTEXT_ACTION) {
- this.executeContextAction(null, e.latlng);
- } else {
- this.setState(IDLE);
- getApp().getUnitsManager().deselectAllUnits();
- }
- }
- }
-
- /* No longer waiting for a doubleclick */
- this.#waitingForDoubleClick = false;
- }, 200);
- }
-
- #onDoubleClick(e: any) {
- /* Let single clicks work again */
- this.#waitingForDoubleClick = false;
- clearTimeout(this.#doubleClickTimer);
-
- this.setState(IDLE);
- }
-
- #onContextMenu(e: any) {}
-
#onDragStart(e: any) {
this.#isDragging = true;
}
@@ -818,27 +654,103 @@ export class Map extends L.Map {
}
#onSelectionStart(e: any) {
- this.#isSelecting = true;
}
#onSelectionEnd(e: any) {
- this.#isSelecting = false;
- clearTimeout(this.#leftClickTimer);
- this.#preventLeftClick = true;
- this.#leftClickTimer = window.setTimeout(() => {
- this.#preventLeftClick = false;
- }, 200);
getApp().getUnitsManager().selectFromBounds(e.selectionBounds);
document.dispatchEvent(new CustomEvent("mapSelectionEnd"));
}
#onMouseUp(e: any) {
+ this.#isMouseDown = false;
window.clearTimeout(this.#longPressTimer);
+
+ this.#isMouseOnCooldown = true;
+ this.#mouseCooldownTimer = window.setTimeout(() => {
+ this.#isMouseOnCooldown = false;
+ }, 200);
}
#onMouseDown(e: any) {
+ this.#isMouseDown = true;
+
+ if (this.#isMouseOnCooldown) {
+ return;
+ }
+
+ this.#shortPressTimer = window.setTimeout(() => {
+ /* If the mouse is no longer being pressed, execute the short press action */
+ if (!this.#isMouseDown) this.#onShortPress(e);
+ }, 200);
+
this.#longPressTimer = window.setTimeout(() => {
- if (!this.#isDragging && !this.#isZooming)
+ /* If the mouse is still being pressed, execute the long press action */
+ if (this.#isMouseDown) this.#onLongPress(e);
+ }, 500);
+ }
+
+ #onDoubleClick(e: any) {
+ console.log(`Double click at ${e.latlng}`);
+
+ window.clearTimeout(this.#shortPressTimer);
+ window.clearTimeout(this.#longPressTimer);
+
+ if (this.#state === COALITIONAREA_DRAW_POLYGON) {
+ this.setState(COALITIONAREA_EDIT);
+ } else {
+ this.setState(IDLE);
+ }
+ }
+
+ #onShortPress(e: any) {
+ console.log(`Short press at ${e.latlng}`);
+
+ const location = new L.LatLng(e.latlng.lat, e.latlng.lng);
+
+ /* Execute the short click action */
+ if (this.#state === IDLE) {
+ this.deselectAllCoalitionAreas();
+ } else if (this.#state === SPAWN_UNIT) {
+ if (this.#spawnRequestTable !== null) {
+ this.#spawnRequestTable.unit.location = location;
+ getApp()
+ .getUnitsManager()
+ .spawnUnits(
+ this.#spawnRequestTable.category,
+ [this.#spawnRequestTable.unit],
+ this.#spawnRequestTable.coalition,
+ false,
+ undefined,
+ undefined,
+ (hash) => {
+ this.addTemporaryMarker(
+ location,
+ this.#spawnRequestTable?.unit.unitType ?? "unknown",
+ this.#spawnRequestTable?.coalition ?? "blue",
+ hash
+ );
+ }
+ );
+ }
+ } else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
+ if (this.getSelectedCoalitionArea()?.getEditing()) {
+ this.getSelectedCoalitionArea()?.addTemporaryLatLng(location);
+ } else {
+ this.deselectAllCoalitionAreas();
+ }
+ } else if (this.#state === COALITIONAREA_EDIT) {
+ this.deselectAllCoalitionAreas();
+ } else if (this.#state === CONTEXT_ACTION) {
+ this.executeContextAction(null, e.latlng);
+ } else {
+ }
+ }
+
+ #onLongPress(e: any) {
+ console.log(`Long press at ${e.latlng}`);
+
+ if (!this.#isDragging && !this.#isZooming) {
+ if (this.getState() == IDLE) {
if (e.type === "touchstart")
document.dispatchEvent(
new CustomEvent("mapForceBoxSelect", { detail: e })
@@ -847,36 +759,50 @@ export class Map extends L.Map {
document.dispatchEvent(
new CustomEvent("mapForceBoxSelect", { detail: e.originalEvent })
);
- }, 500);
+ } else if (this.getState() == COALITIONAREA_EDIT) {
+ for (let idx = 0; idx < this.#coalitionAreas.length; idx++) {
+ if (polyContains(e.latlng, this.#coalitionAreas[idx])) {
+ this.#coalitionAreas[idx].setSelected(true);
+ break;
+ }
+ }
+ }
+ }
}
#onMouseMove(e: any) {
+ window.clearTimeout(this.#longPressTimer);
+
this.#lastMousePosition.x = e.originalEvent.x;
this.#lastMousePosition.y = e.originalEvent.y;
this.#lastMouseCoordinates = this.mouseEventToLatLng(e.originalEvent);
if (this.#state === COALITIONAREA_DRAW_POLYGON && e.latlng !== undefined) {
/* Update the polygon being drawn with the current position of the mouse cursor */
- this.getSelectedCoalitionArea()?.moveActiveVertex(e.latlng);
+ //this.getSelectedCoalitionArea()?.moveActiveVertex(e.latlng);
}
}
+ #onMapMove(e: any) {
+ if (this.#slaveDCSCamera) this.#broadcastPosition();
+ }
+
#onKeyDown(e: any) {
- this.#shiftKey = e.originalEvent.shiftKey;
+ this.#isShiftKeyDown = e.originalEvent.shiftKey;
}
#onKeyUp(e: any) {
- this.#shiftKey = e.originalEvent.shiftKey;
+ this.#isShiftKeyDown = e.originalEvent.shiftKey;
}
#onZoomStart(e: any) {
this.#previousZoom = this.getZoom();
- if (this.#centerUnit != null) this.#panToUnit(this.#centerUnit);
+ if (this.#centeredUnit != null) this.#panToUnit(this.#centeredUnit);
this.#isZooming = true;
}
#onZoom(e: any) {
- if (this.#centerUnit != null) this.#panToUnit(this.#centerUnit);
+ if (this.#centeredUnit != null) this.#panToUnit(this.#centeredUnit);
}
#onZoomEnd(e: any) {
diff --git a/frontend/react/src/map/markers/smokemarker.ts b/frontend/react/src/map/markers/smokemarker.ts
index b8a99c6e..cf20e4dc 100644
--- a/frontend/react/src/map/markers/smokemarker.ts
+++ b/frontend/react/src/map/markers/smokemarker.ts
@@ -31,7 +31,7 @@ export class SmokeMarker extends CustomMarker {
el.classList.add("ol-smoke-icon");
el.setAttribute("data-color", this.#color);
var img = document.createElement("img");
- img.src = "/images/markers/smoke.svg";
+ img.src = "/vite/images/markers/smoke.svg";
img.onload = () => SVGInjector(img);
el.appendChild(img);
this.getElement()?.appendChild(el);
diff --git a/frontend/react/src/map/markers/stylesheets/units.css b/frontend/react/src/map/markers/stylesheets/units.css
index 7b46717f..32de33e9 100644
--- a/frontend/react/src/map/markers/stylesheets/units.css
+++ b/frontend/react/src/map/markers/stylesheets/units.css
@@ -288,15 +288,15 @@
}
[data-object|="unit"][data-state="rtb"] .unit-state {
- background-image: url("/images/states/rtb.svg");
+ background-image: url("/vite/images/states/rtb.svg");
}
[data-object|="unit"][data-state="land"] .unit-state {
- background-image: url("/images/states/rtb.svg");
+ background-image: url("/vite/images/states/rtb.svg");
}
[data-object|="unit"][data-state="idle"] .unit-state {
- background-image: url("/images/states/idle.svg");
+ background-image: url("/vite/images/states/idle.svg");
}
[data-object*="groundunit"][data-state="idle"] .unit-state,
@@ -308,59 +308,59 @@
[data-object|="unit"][data-state="bomb-point"] .unit-state,
[data-object|="unit"][data-state="carpet-bombing"] .unit-state,
[data-object|="unit"][data-state="fire-at-area"] .unit-state {
- background-image: url("/images/states/attack.svg");
+ background-image: url("/vite/images/states/attack.svg");
}
[data-object|="unit"][data-state="follow"] .unit-state {
- background-image: url("/images/states/follow.svg");
+ background-image: url("/vite/images/states/follow.svg");
}
[data-object|="unit"][data-state="refuel"] .unit-state {
- background-image: url("/images/states/refuel.svg");
+ background-image: url("/vite/images/states/refuel.svg");
}
[data-object|="unit"][data-state="human"] .unit-state {
- background-image: url("/images/states/human.svg");
+ background-image: url("/vite/images/states/human.svg");
}
[data-object|="unit"][data-state="dcs"] .unit-state {
- background-image: url("/images/states/dcs.svg");
+ background-image: url("/vite/images/states/dcs.svg");
}
[data-object|="unit"][data-state="land-at-point"] .unit-state {
- background-image: url("/images/states/land-at-point.svg");
+ background-image: url("/vite/images/states/land-at-point.svg");
}
[data-object|="unit"][data-state="no-task"] .unit-state {
- background-image: url("/images/states/no-task.svg");
+ background-image: url("/vite/images/states/no-task.svg");
}
[data-object|="unit"][data-state="off"] .unit-state {
- background-image: url("/images/states/off.svg");
+ background-image: url("/vite/images/states/off.svg");
}
[data-object|="unit"][data-state="tanker"] .unit-state {
- background-image: url("/images/states/tanker.svg");
+ background-image: url("/vite/images/states/tanker.svg");
}
[data-object|="unit"][data-state="AWACS"] .unit-state {
- background-image: url("/images/states/awacs.svg");
+ background-image: url("/vite/images/states/awacs.svg");
}
[data-object|="unit"][data-state="miss-on-purpose"] .unit-state {
- background-image: url("/images/states/miss-on-purpose.svg");
+ background-image: url("/vite/images/states/miss-on-purpose.svg");
}
[data-object|="unit"][data-state="scenic-aaa"] .unit-state {
- background-image: url("/images/states/scenic-aaa.svg");
+ background-image: url("/vite/images/states/scenic-aaa.svg");
}
[data-object|="unit"][data-state="simulate-fire-fight"] .unit-state {
- background-image: url("/images/states/simulate-fire-fight.svg");
+ background-image: url("/vite/images/states/simulate-fire-fight.svg");
}
[data-object|="unit"] .unit-health::before {
- background-image: url("/images/icons/health.svg");
+ background-image: url("/vite/images/icons/health.svg");
background-repeat: no-repeat;
background-size: contain;
content: " ";
diff --git a/frontend/react/src/map/markers/temporaryunitmarker.ts b/frontend/react/src/map/markers/temporaryunitmarker.ts
index 72a09228..76eca34a 100644
--- a/frontend/react/src/map/markers/temporaryunitmarker.ts
+++ b/frontend/react/src/map/markers/temporaryunitmarker.ts
@@ -67,7 +67,7 @@ export class TemporaryUnitMarker extends CustomMarker {
unitIcon.classList.add("unit-icon");
var img = document.createElement("img");
- img.src = `/images/units/${databaseEntry?.markerFile ?? category}.svg`;
+ img.src = `/vite/images/units/${databaseEntry?.markerFile ?? category}.svg`;
img.onload = () => SVGInjector(img);
unitIcon.appendChild(img);
unitIcon.toggleAttribute("data-rotate-to-heading", false);
diff --git a/frontend/react/src/map/touchboxselect.ts b/frontend/react/src/map/touchboxselect.ts
deleted file mode 100644
index fe531e4b..00000000
--- a/frontend/react/src/map/touchboxselect.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-import { Map, Point } 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";
-
-export var TouchBoxSelect = Handler.extend({
- initialize: function (map: Map) {
- this._map = map;
- this._container = map.getContainer();
- this._pane = map.getPanes().overlayPane;
- this._resetStateTimeout = 0;
- this._doubleClicked = false;
- map.on("unload", this._destroy, this);
- },
-
- addHooks: function () {
- DomEvent.on(this._container, "touchstart", this._onMouseDown, this);
- },
-
- removeHooks: function () {
- DomEvent.off(this._container, "touchstart", this._onMouseDown, this);
- },
-
- moved: function () {
- return this._moved;
- },
-
- _destroy: function () {
- DomUtil.remove(this._pane);
- delete this._pane;
- },
-
- _resetState: function () {
- this._resetStateTimeout = 0;
- this._moved = false;
- },
-
- _clearDeferredResetState: function () {
- if (this._resetStateTimeout !== 0) {
- clearTimeout(this._resetStateTimeout);
- this._resetStateTimeout = 0;
- }
- },
-
- _onMouseDown: function (e: any) {
- if (e.which == 0) {
- this._map.fire("selectionstart");
- // Clear the deferred resetState if it hasn't executed yet, otherwise it
- // will interrupt the interaction and orphan a box element in the container.
- this._clearDeferredResetState();
- this._resetState();
-
- DomUtil.disableTextSelection();
- DomUtil.disableImageDrag();
-
- this._startPoint = this._getMousePosition(e);
-
- //@ts-ignore
- DomEvent.on(
- document,
- {
- contextmenu: DomEvent.stop,
- touchmove: this._onMouseMove,
- touchend: this._onMouseUp,
- },
- this
- );
- } else {
- return false;
- }
- },
-
- _onMouseMove: function (e: any) {
- if (!this._moved) {
- this._moved = true;
-
- this._box = DomUtil.create("div", "leaflet-zoom-box", this._container);
- DomUtil.addClass(this._container, "leaflet-crosshair");
- }
-
- this._point = this._getMousePosition(e);
-
- var bounds = new Bounds(this._point, this._startPoint),
- size = bounds.getSize();
-
- if (bounds.min != undefined) DomUtil.setPosition(this._box, bounds.min);
-
- this._box.style.width = size.x + "px";
- this._box.style.height = size.y + "px";
- },
-
- _finish: function () {
- if (this._moved) {
- DomUtil.remove(this._box);
- DomUtil.removeClass(this._container, "leaflet-crosshair");
- }
-
- DomUtil.enableTextSelection();
- DomUtil.enableImageDrag();
-
- //@ts-ignore
- DomEvent.off(
- document,
- {
- contextmenu: DomEvent.stop,
- touchmove: this._onMouseMove,
- touchend: this._onMouseUp,
- },
- this
- );
- },
-
- _onMouseUp: function (e: any) {
- if (e.which !== 0) {
- return;
- }
-
- this._finish();
-
- if (!this._moved) {
- return;
- }
- // Postpone to next JS tick so internal click event handling
- // still see it as "moved".
- window.setTimeout(Util.bind(this._resetState, this), 0);
- var bounds = new LatLngBounds(
- this._map.containerPointToLatLng(this._startPoint),
- this._map.containerPointToLatLng(this._point)
- );
-
- this._map.fire("selectionend", { selectionBounds: bounds });
- },
-
- _getMousePosition(e: any) {
- var scale = DomUtil.getScale(this._container),
- offset = scale.boundingClientRect; // left and top values are in page scale (like the event clientX/Y)
-
- return new Point(
- // offset.left/top values are in page scale (like clientX/Y),
- // whereas clientLeft/Top (border width) values are the original values (before CSS scale applies).
- (e.touches[0].clientX - offset.left) / scale.x -
- this._container.clientLeft,
- (e.touches[0].clientY - offset.top) / scale.y - this._container.clientTop
- );
- },
-});
diff --git a/frontend/react/src/mission/airbase.ts b/frontend/react/src/mission/airbase.ts
index 50b82851..70a81746 100644
--- a/frontend/react/src/mission/airbase.ts
+++ b/frontend/react/src/mission/airbase.ts
@@ -38,7 +38,7 @@ export class Airbase extends CustomMarker {
el.classList.add("airbase-icon");
el.setAttribute("data-object", "airbase");
var img = document.createElement("img");
- img.src = "/images/markers/airbase.svg";
+ img.src = "/vite/images/markers/airbase.svg";
img.onload = () => SVGInjector(img);
el.appendChild(img);
this.getElement()?.appendChild(el);
diff --git a/frontend/react/src/mission/bullseye.ts b/frontend/react/src/mission/bullseye.ts
index b1149780..6a343720 100644
--- a/frontend/react/src/mission/bullseye.ts
+++ b/frontend/react/src/mission/bullseye.ts
@@ -17,7 +17,7 @@ export class Bullseye extends CustomMarker {
el.classList.add("bullseye-icon");
el.setAttribute("data-object", "bullseye");
var img = document.createElement("img");
- img.src = "/images/markers/bullseye.svg";
+ img.src = "/vite/images/markers/bullseye.svg";
img.onload = () => SVGInjector(img);
el.appendChild(img);
this.getElement()?.appendChild(el);
diff --git a/frontend/react/src/olympusapp.ts b/frontend/react/src/olympusapp.ts
index 2449aa0c..ca55ac8c 100644
--- a/frontend/react/src/olympusapp.ts
+++ b/frontend/react/src/olympusapp.ts
@@ -210,7 +210,7 @@ export class OlympusApp {
/* Load the config file from the server */
const configRequest = new Request(
- window.location.href.split("?")[0].replace("vite/", "") +
+ window.location.href.split("?")[0].replace("/vite", "/") +
"resources/config"
);
fetch(configRequest)
diff --git a/frontend/react/src/server/servermanager.ts b/frontend/react/src/server/servermanager.ts
index a01ea1f5..8540e013 100644
--- a/frontend/react/src/server/servermanager.ts
+++ b/frontend/react/src/server/servermanager.ts
@@ -175,7 +175,7 @@ export class ServerManager {
}
setAddress(address: string) {
- this.#REST_ADDRESS = `${address}olympus`;
+ this.#REST_ADDRESS = `${address.replace('vite', '')}olympus`;
console.log(`Setting REST address to ${this.#REST_ADDRESS}`);
}
diff --git a/frontend/react/src/ui/components/olstatebutton.tsx b/frontend/react/src/ui/components/olstatebutton.tsx
index 6ef85455..7d343e8a 100644
--- a/frontend/react/src/ui/components/olstatebutton.tsx
+++ b/frontend/react/src/ui/components/olstatebutton.tsx
@@ -16,6 +16,7 @@ export function OlStateButton(props: {
icon: IconProp;
tooltip: string;
onClick: () => void;
+ children?: JSX.Element | JSX.Element[];
}) {
var [hover, setHover] = useState(false);
var buttonRef = useRef(null);
@@ -47,7 +48,10 @@ export function OlStateButton(props: {
setHover(false);
}}
>
-
+
+
+ {props.children}
+
{hover && }
>
diff --git a/frontend/react/src/ui/components/olunitsummary.tsx b/frontend/react/src/ui/components/olunitsummary.tsx
index 1f037e3e..2e184361 100644
--- a/frontend/react/src/ui/components/olunitsummary.tsx
+++ b/frontend/react/src/ui/components/olunitsummary.tsx
@@ -23,7 +23,7 @@ export function OlUnitSummary(props: {
className={`
absolute right-5 top-0 h-full object-cover opacity-10 invert
`}
- src={"images/units/" + props.blueprint.filename}
+ src={"vite/images/units/" + props.blueprint.filename}
alt=""
/>
@@ -332,7 +332,7 @@ export function LoginModal(props: {
>
void }) {
+ const [drawingPolygon, setDrawingPolygon] = useState(false);
+
+ useEffect(() => {
+ if (props.open && !drawingPolygon) {
+ getApp().getMap().setState(COALITIONAREA_EDIT);
+ }
+ })
+
+ return (
+
+ );
+}
diff --git a/frontend/react/src/ui/panels/header.tsx b/frontend/react/src/ui/panels/header.tsx
index 1a039026..51992046 100644
--- a/frontend/react/src/ui/panels/header.tsx
+++ b/frontend/react/src/ui/panels/header.tsx
@@ -60,7 +60,7 @@ export function Header() {
`}
>
{!scrolledLeft && (
diff --git a/frontend/react/src/ui/panels/unitcontrolmenu.tsx b/frontend/react/src/ui/panels/unitcontrolmenu.tsx
index 7e17a8a7..2594ed24 100644
--- a/frontend/react/src/ui/panels/unitcontrolmenu.tsx
+++ b/frontend/react/src/ui/panels/unitcontrolmenu.tsx
@@ -35,10 +35,7 @@ import {
import { Coalition } from "../../types/types";
import { ftToM, knotsToMs, mToFt, msToKnots } from "../../other/utils";
-export function UnitControlMenu(props: {
- open: boolean;
- onClose: () => void;
-}) {
+export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
var [selectedUnits, setSelectedUnits] = useState([] as Unit[]);
var [selectedUnitsData, setSelectedUnitsData] = useState({
@@ -185,7 +182,12 @@ export function UnitControlMenu(props: {
getApp()?.getUnitsManager()?.getSelectedUnitsCategories() ?? [];
return (
-