mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat: Control scheme improvement
This commit is contained in:
parent
0b8fb969b2
commit
eff96ce0c2
@ -16,13 +16,13 @@ export var BoxSelect = Handler.extend({
|
||||
},
|
||||
|
||||
addHooks: function () {
|
||||
DomEvent.on(this._container, "mousedown", this._onMouseDown, this);
|
||||
DomEvent.on(this._container, "touchstart", this._onMouseDown, this);
|
||||
if ("ontouchstart" in window) DomEvent.on(this._container, "touchend", this._onMouseDown, this);
|
||||
else DomEvent.on(this._container, "mousedown", this._onMouseDown, this);
|
||||
},
|
||||
|
||||
removeHooks: function () {
|
||||
DomEvent.off(this._container, "mousedown", this._onMouseDown, this);
|
||||
DomEvent.off(this._container, "touchend", this._onMouseDown, this);
|
||||
if ("ontouchstart" in window) DomEvent.off(this._container, "touchstart", this._onMouseDown, this);
|
||||
else DomEvent.off(this._container, "mousedown", this._onMouseDown, this);
|
||||
},
|
||||
|
||||
moved: function () {
|
||||
@ -48,18 +48,29 @@ export var BoxSelect = Handler.extend({
|
||||
if (e.type === "touchstart") this._startPoint = this._map.mouseEventToContainerPoint(e.touches[0]);
|
||||
else this._startPoint = this._map.mouseEventToContainerPoint(e);
|
||||
|
||||
DomEvent.on(
|
||||
//@ts-ignore
|
||||
document,
|
||||
{
|
||||
contextmenu: DomEvent.stop,
|
||||
touchmove: this._onMouseMove,
|
||||
touchend: this._onMouseUp,
|
||||
mousemove: this._onMouseMove,
|
||||
mouseup: this._onMouseUp,
|
||||
},
|
||||
this
|
||||
);
|
||||
if ("ontouchstart" in window) {
|
||||
DomEvent.on(
|
||||
//@ts-ignore
|
||||
document,
|
||||
{
|
||||
contextmenu: DomEvent.stop,
|
||||
touchmove: this._onMouseMove,
|
||||
touchend: this._onMouseUp,
|
||||
},
|
||||
this
|
||||
);
|
||||
} else {
|
||||
DomEvent.on(
|
||||
//@ts-ignore
|
||||
document,
|
||||
{
|
||||
contextmenu: DomEvent.stop,
|
||||
mousemove: this._onMouseMove,
|
||||
mouseup: this._onMouseUp,
|
||||
},
|
||||
this
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -109,18 +120,29 @@ export var BoxSelect = Handler.extend({
|
||||
DomUtil.enableImageDrag();
|
||||
this._map.dragging.enable();
|
||||
|
||||
DomEvent.off(
|
||||
//@ts-ignore
|
||||
document,
|
||||
{
|
||||
contextmenu: DomEvent.stop,
|
||||
touchmove: this._onMouseMove,
|
||||
touchend: this._onMouseUp,
|
||||
mousemove: this._onMouseMove,
|
||||
mouseup: this._onMouseUp,
|
||||
},
|
||||
this
|
||||
);
|
||||
if ("ontouchstart" in window) {
|
||||
DomEvent.off(
|
||||
//@ts-ignore
|
||||
document,
|
||||
{
|
||||
contextmenu: DomEvent.stop,
|
||||
touchmove: this._onMouseMove,
|
||||
touchend: this._onMouseUp,
|
||||
},
|
||||
this
|
||||
);
|
||||
} else {
|
||||
DomEvent.off(
|
||||
//@ts-ignore
|
||||
document,
|
||||
{
|
||||
contextmenu: DomEvent.stop,
|
||||
mousemove: this._onMouseMove,
|
||||
mouseup: this._onMouseUp,
|
||||
},
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
this._resetState();
|
||||
},
|
||||
|
||||
@ -3,7 +3,7 @@ import { getApp } from "../olympusapp";
|
||||
import { BoxSelect } from "./boxselect";
|
||||
import { Airbase } from "../mission/airbase";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { areaContains, deepCopyTable, deg2rad, getGroundElevation } from "../other/utils";
|
||||
import { areaContains, deepCopyTable, deg2rad, getGroundElevation, getMagvar, rad2deg } from "../other/utils";
|
||||
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
|
||||
import { ClickableMiniMap } from "./clickableminimap";
|
||||
import {
|
||||
@ -70,6 +70,7 @@ import { ContextActionSet } from "../unit/contextactionset";
|
||||
import { SmokeMarker } from "./markers/smokemarker";
|
||||
import { Measure } from "./measure";
|
||||
import { FlakMarker } from "./markers/flakmarker";
|
||||
import { MapMouseHandler } from "./mapMouseHandler";
|
||||
|
||||
/* Register the handler for the box selection */
|
||||
L.Map.addInitHook("addHandler", "boxSelect", BoxSelect);
|
||||
@ -110,14 +111,8 @@ export class Map extends L.Map {
|
||||
#isDragging: boolean = false;
|
||||
#isSelecting: boolean = false;
|
||||
|
||||
#originalMouseClickLatLng: L.LatLng | null = null;
|
||||
#debounceTimeout: number | null = null;
|
||||
#isLeftMouseDown: boolean = false;
|
||||
#isRightMouseDown: boolean = false;
|
||||
#leftMouseDownEpoch: number = 0;
|
||||
#rightMouseDownEpoch: number = 0;
|
||||
#leftMouseDownTimeout: number = 0;
|
||||
#rightMouseDownTimeout: number = 0;
|
||||
#mouseHandler: MapMouseHandler = new MapMouseHandler(this);
|
||||
|
||||
#lastMousePosition: L.Point = new L.Point(0, 0);
|
||||
#lastMouseCoordinates: L.LatLng = new L.LatLng(0, 0);
|
||||
#previousZoom: number = 0;
|
||||
@ -139,7 +134,7 @@ export class Map extends L.Map {
|
||||
#destinationPreviewMarkers: { [key: number]: TemporaryUnitMarker | TargetMarker } = {};
|
||||
#destinationRotation: number = 0;
|
||||
#isRotatingDestination: boolean = false;
|
||||
#destionationWasRotated: boolean = false;
|
||||
#destinationRotationCenter: L.LatLng = new L.LatLng(0, 0);
|
||||
|
||||
/* Unit context actions */
|
||||
#contextActionSet: null | ContextActionSet = null;
|
||||
@ -209,22 +204,20 @@ export class Map extends L.Map {
|
||||
this.on("selectionstart", (e: any) => this.#onSelectionStart(e));
|
||||
this.on("selectionend", (e: any) => this.#onSelectionEnd(e));
|
||||
|
||||
this.on("mouseup", (e: any) => this.#onMouseUp(e));
|
||||
this.on("touchend", (e: any) => this.#onMouseUp(e));
|
||||
this.on("mousedown", (e: any) => this.#onMouseDown(e));
|
||||
this.on("touchstart", (e: any) => this.#onMouseDown(e));
|
||||
this.on("dblclick", (e: any) => this.#onDoubleClick(e));
|
||||
this.on("click", (e: any) => e.originalEvent.preventDefault());
|
||||
this.on("contextmenu", (e: any) => e.originalEvent.preventDefault());
|
||||
|
||||
this.on("mousemove", (e: any) => this.#onMouseMove(e));
|
||||
|
||||
this.on("move", (e: any) => this.#onMapMove(e));
|
||||
|
||||
/* Custom touch events for touchscreen support */
|
||||
L.DomEvent.on(this.getContainer(), "touchstart", this.#onMouseDown, this);
|
||||
L.DomEvent.on(this.getContainer(), "touchend", this.#onMouseUp, this);
|
||||
L.DomEvent.on(this.getContainer(), "wheel", this.#onMouseWheel, this);
|
||||
this.#mouseHandler.leftMousePressed = (e: L.LeafletMouseEvent) => this.#onLeftMousePressed(e);
|
||||
this.#mouseHandler.leftMouseReleased = (e: L.LeafletMouseEvent) => this.#onLeftMouseReleased(e);
|
||||
this.#mouseHandler.rightMousePressed = (e: L.LeafletMouseEvent) => this.#onRightMousePressed(e);
|
||||
this.#mouseHandler.rightMouseReleased = (e: L.LeafletMouseEvent) => this.#onRightMouseReleased(e);
|
||||
this.#mouseHandler.mouseWheelPressed = (e: L.LeafletMouseEvent) => this.#onMouseWheelPressed(e);
|
||||
this.#mouseHandler.mouseWheelReleased = (e: L.LeafletMouseEvent) => this.#onMouseWheelReleased(e);
|
||||
this.#mouseHandler.leftMouseShortClick = (e: L.LeafletMouseEvent) => this.#onLeftMouseShortClick(e);
|
||||
this.#mouseHandler.rightMouseShortClick = (e: L.LeafletMouseEvent) => this.#onRightMouseShortClick(e);
|
||||
this.#mouseHandler.leftMouseLongClick = (e: L.LeafletMouseEvent) => this.#onLeftMouseLongClick(e);
|
||||
this.#mouseHandler.rightMouseLongClick = (e: L.LeafletMouseEvent) => this.#onRightMouseLongClick(e);
|
||||
this.#mouseHandler.leftMouseDoubleClick = (e: L.LeafletMouseEvent) => this.#onLeftMouseDoubleClick(e);
|
||||
this.#mouseHandler.mouseMove = (e: L.LeafletMouseEvent) => this.#onMouseMove(e);
|
||||
|
||||
/* Event listeners */
|
||||
AppStateChangedEvent.on((state, subState) => this.#onStateChanged(state, subState));
|
||||
@ -405,14 +398,14 @@ export class Map extends L.Map {
|
||||
altKey: false,
|
||||
ctrlKey: false,
|
||||
})
|
||||
.addShortcut("toggleRelativePositions", {
|
||||
label: "Toggle group movement mode",
|
||||
keyUpCallback: () => this.setKeepRelativePositions(false),
|
||||
keyDownCallback: () => this.setKeepRelativePositions(true),
|
||||
code: "AltLeft",
|
||||
shiftKey: false,
|
||||
ctrlKey: false,
|
||||
})
|
||||
//.addShortcut("toggleRelativePositions", {
|
||||
// label: "Toggle group movement mode",
|
||||
// keyUpCallback: () => this.setKeepRelativePositions(false),
|
||||
// keyDownCallback: () => this.setKeepRelativePositions(true),
|
||||
// code: "AltLeft",
|
||||
// shiftKey: false,
|
||||
// ctrlKey: false,
|
||||
//})
|
||||
.addShortcut("toggleSelectionEnabled", {
|
||||
label: "Toggle box selection",
|
||||
keyUpCallback: () => this.setSelectionEnabled(false),
|
||||
@ -510,7 +503,7 @@ export class Map extends L.Map {
|
||||
code: "ShiftLeft",
|
||||
altKey: false,
|
||||
ctrlKey: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
setLayerName(layerName: string) {
|
||||
@ -803,8 +796,6 @@ export class Map extends L.Map {
|
||||
setKeepRelativePositions(keepRelativePositions: boolean) {
|
||||
this.#keepRelativePositions = keepRelativePositions;
|
||||
this.#updateDestinationPreviewMarkers();
|
||||
if (keepRelativePositions) this.scrollWheelZoom.disable();
|
||||
else this.scrollWheelZoom.enable();
|
||||
}
|
||||
|
||||
getKeepRelativePositions() {
|
||||
@ -960,7 +951,10 @@ export class Map extends L.Map {
|
||||
}
|
||||
|
||||
#onDragEnd(e: any) {
|
||||
this.#isDragging = false;
|
||||
/* Delay the drag end event so that any other event in the queue still sees the map in dragging mode */
|
||||
window.setTimeout(() => {
|
||||
this.#isDragging = false;
|
||||
}, SHORT_PRESS_MILLISECONDS + 100);
|
||||
}
|
||||
|
||||
#onSelectionStart(e: any) {
|
||||
@ -976,201 +970,219 @@ export class Map extends L.Map {
|
||||
/* Delay the event so that any other event in the queue still sees the map in selection mode */
|
||||
window.setTimeout(() => {
|
||||
this.#isSelecting = false;
|
||||
}, 300);
|
||||
}, SHORT_PRESS_MILLISECONDS + 100);
|
||||
}
|
||||
|
||||
#onMouseUp(e: any) {
|
||||
#onLeftMouseReleased(e: any) {
|
||||
this.dragging.enable();
|
||||
|
||||
if (e.originalEvent?.button === 0) {
|
||||
if (Date.now() - this.#leftMouseDownEpoch < SHORT_PRESS_MILLISECONDS) this.#onLeftShortClick(e);
|
||||
this.#isLeftMouseDown = false;
|
||||
} else if (e.originalEvent?.button === 2) {
|
||||
if (Date.now() - this.#rightMouseDownEpoch < SHORT_PRESS_MILLISECONDS) this.#onRightShortClick(e);
|
||||
this.#isRightMouseDown = false;
|
||||
} else if (e.originalEvent?.button === 1) {
|
||||
getApp().setState(getApp().getState() === OlympusState.MEASURE ? OlympusState.IDLE : OlympusState.MEASURE);
|
||||
if (getApp().getState() === OlympusState.MEASURE) {
|
||||
const newMeasure = new Measure(this);
|
||||
const previousMeasure = this.#measures[this.#measures.length - 1];
|
||||
this.#measures.push(newMeasure);
|
||||
newMeasure.onClick(e.latlng);
|
||||
if (previousMeasure && previousMeasure.isActive()) {
|
||||
previousMeasure.finish();
|
||||
previousMeasure.hideEndMarker();
|
||||
newMeasure.onMarkerMoved = (startLatLng, endLatLng) => {
|
||||
previousMeasure.moveMarkers(null, startLatLng);
|
||||
};
|
||||
}
|
||||
if (this.#isRotatingDestination && getApp().getState() === OlympusState.UNIT_CONTROL && this.getContextAction() !== null) {
|
||||
this.executeContextAction(null, this.#destinationRotationCenter, e.originalEvent);
|
||||
}
|
||||
this.#isRotatingDestination = false;
|
||||
this.setKeepRelativePositions(false);
|
||||
|
||||
/* Delay the event so that any other event in the queue still sees the map in selection mode */
|
||||
window.setTimeout(() => {
|
||||
this.setSelectionEnabled(false);
|
||||
this.#isSelecting = false;
|
||||
}, SHORT_PRESS_MILLISECONDS + 100);
|
||||
}
|
||||
|
||||
#onMouseWheelReleased(e: any) {
|
||||
this.dragging.enable();
|
||||
|
||||
getApp().setState(getApp().getState() === OlympusState.MEASURE ? OlympusState.IDLE : OlympusState.MEASURE);
|
||||
if (getApp().getState() === OlympusState.MEASURE) {
|
||||
const newMeasure = new Measure(this);
|
||||
const previousMeasure = this.#measures[this.#measures.length - 1];
|
||||
this.#measures.push(newMeasure);
|
||||
newMeasure.onClick(e.latlng);
|
||||
if (previousMeasure && previousMeasure.isActive()) {
|
||||
previousMeasure.finish();
|
||||
previousMeasure.hideEndMarker();
|
||||
newMeasure.onMarkerMoved = (startLatLng, endLatLng) => {
|
||||
previousMeasure.moveMarkers(null, startLatLng);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#onMouseDown(e: any) {
|
||||
if (e.originalEvent?.button === 1) {
|
||||
this.dragging.disable();
|
||||
} // Disable dragging when right clicking
|
||||
#onRightMouseReleased(e: any) {
|
||||
this.dragging.enable();
|
||||
|
||||
this.#originalMouseClickLatLng = e.latlng;
|
||||
if (e.originalEvent?.button === 0) {
|
||||
this.#isLeftMouseDown = true;
|
||||
this.#leftMouseDownEpoch = Date.now();
|
||||
} else if (e.originalEvent?.button === 2) {
|
||||
this.#isRightMouseDown = true;
|
||||
this.#rightMouseDownEpoch = Date.now();
|
||||
this.#rightMouseDownTimeout = window.setTimeout(() => {
|
||||
this.#onRightLongClick(e);
|
||||
}, SHORT_PRESS_MILLISECONDS);
|
||||
if (this.#isRotatingDestination && getApp().getState() === OlympusState.UNIT_CONTROL) {
|
||||
this.executeDefaultContextAction(null, this.#destinationRotationCenter, e.originalEvent);
|
||||
}
|
||||
this.#isRotatingDestination = false;
|
||||
this.setKeepRelativePositions(false);
|
||||
}
|
||||
|
||||
#onLeftMousePressed(e: any) {
|
||||
if (getApp().getState() === OlympusState.UNIT_CONTROL && getApp().getSubState() === UnitControlSubState.MAP_CONTEXT_MENU) {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL);
|
||||
}
|
||||
}
|
||||
|
||||
#onMouseWheel(e: any) {
|
||||
if (this.#keepRelativePositions) {
|
||||
this.#destinationRotation += e.deltaY / 20;
|
||||
this.#moveDestinationPreviewMarkers();
|
||||
}
|
||||
#onMouseWheelPressed(e: any) {}
|
||||
|
||||
#onRightMousePressed(e: any) {
|
||||
this.dragging.disable();
|
||||
}
|
||||
|
||||
#onLeftShortClick(e: L.LeafletMouseEvent) {
|
||||
#onLeftMouseShortClick(e: L.LeafletMouseEvent) {
|
||||
CoordinatesFreezeEvent.dispatch();
|
||||
if (Date.now() - this.#leftMouseDownEpoch < SHORT_PRESS_MILLISECONDS) {
|
||||
this.#debounceTimeout = window.setTimeout(() => {
|
||||
if (!this.#isSelecting) {
|
||||
console.log(`Left short click at ${e.latlng}`);
|
||||
|
||||
if (this.#pasteEnabled) {
|
||||
getApp().getUnitsManager().paste(e.latlng);
|
||||
}
|
||||
if (this.#isDragging || this.#isSelecting) return;
|
||||
console.log(`Left short click at ${e.latlng}`);
|
||||
|
||||
/* Execute the short click action */
|
||||
if (getApp().getState() === OlympusState.IDLE) {
|
||||
/* Do nothing */
|
||||
} else if (getApp().getState() === OlympusState.SPAWN) {
|
||||
if (getApp().getSubState() === SpawnSubState.SPAWN_UNIT) {
|
||||
if (this.#spawnRequestTable !== null) {
|
||||
this.#spawnRequestTable.unit.location = e.latlng;
|
||||
this.#spawnRequestTable.unit.heading = deg2rad(this.#spawnHeading);
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.spawnUnits(
|
||||
this.#spawnRequestTable.category,
|
||||
Array(this.#spawnRequestTable.amount).fill(this.#spawnRequestTable.unit),
|
||||
this.#spawnRequestTable.coalition,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
(hash) => {
|
||||
this.addTemporaryMarker(
|
||||
e.latlng,
|
||||
this.#spawnRequestTable?.unit.unitType ?? "unknown",
|
||||
this.#spawnRequestTable?.coalition ?? "blue",
|
||||
false,
|
||||
hash
|
||||
);
|
||||
}
|
||||
);
|
||||
if (this.#pasteEnabled) {
|
||||
getApp().getUnitsManager().paste(e.latlng);
|
||||
}
|
||||
|
||||
/* Execute the short click action */
|
||||
if (getApp().getState() === OlympusState.IDLE) {
|
||||
/* Do nothing */
|
||||
} else if (getApp().getState() === OlympusState.SPAWN) {
|
||||
if (getApp().getSubState() === SpawnSubState.SPAWN_UNIT) {
|
||||
if (this.#spawnRequestTable !== null) {
|
||||
this.#spawnRequestTable.unit.location = e.latlng;
|
||||
this.#spawnRequestTable.unit.heading = deg2rad(this.#spawnHeading);
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.spawnUnits(
|
||||
this.#spawnRequestTable.category,
|
||||
Array(this.#spawnRequestTable.amount).fill(this.#spawnRequestTable.unit),
|
||||
this.#spawnRequestTable.coalition,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
(hash) => {
|
||||
this.addTemporaryMarker(
|
||||
e.latlng,
|
||||
this.#spawnRequestTable?.unit.unitType ?? "unknown",
|
||||
this.#spawnRequestTable?.coalition ?? "blue",
|
||||
false,
|
||||
hash
|
||||
);
|
||||
}
|
||||
} else if (getApp().getSubState() === SpawnSubState.SPAWN_EFFECT) {
|
||||
if (this.#effectRequestTable !== null) {
|
||||
if (this.#effectRequestTable.type === "explosion") {
|
||||
if (this.#effectRequestTable.explosionType === "High explosive") getApp().getServerManager().spawnExplosion(50, "normal", e.latlng);
|
||||
else if (this.#effectRequestTable.explosionType === "Napalm") getApp().getServerManager().spawnExplosion(50, "napalm", e.latlng);
|
||||
else if (this.#effectRequestTable.explosionType === "White phosphorous")
|
||||
getApp().getServerManager().spawnExplosion(50, "phosphorous", e.latlng);
|
||||
);
|
||||
}
|
||||
} else if (getApp().getSubState() === SpawnSubState.SPAWN_EFFECT) {
|
||||
if (this.#effectRequestTable !== null) {
|
||||
if (this.#effectRequestTable.type === "explosion") {
|
||||
if (this.#effectRequestTable.explosionType === "High explosive") getApp().getServerManager().spawnExplosion(50, "normal", e.latlng);
|
||||
else if (this.#effectRequestTable.explosionType === "Napalm") getApp().getServerManager().spawnExplosion(50, "napalm", e.latlng);
|
||||
else if (this.#effectRequestTable.explosionType === "White phosphorous") getApp().getServerManager().spawnExplosion(50, "phosphorous", e.latlng);
|
||||
|
||||
this.addExplosionMarker(e.latlng);
|
||||
} else if (this.#effectRequestTable.type === "smoke") {
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.spawnSmoke(this.#effectRequestTable.smokeColor ?? "white", e.latlng);
|
||||
this.addSmokeMarker(e.latlng, this.#effectRequestTable.smokeColor ?? "white");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (getApp().getState() === OlympusState.DRAW) {
|
||||
getApp().getCoalitionAreasManager().onLeftShortClick(e);
|
||||
} else if (getApp().getState() === OlympusState.JTAC) {
|
||||
// TODO less redundant way to do this
|
||||
if (getApp().getSubState() === JTACSubState.SELECT_TARGET) {
|
||||
if (!this.#targetPoint) {
|
||||
this.#targetPoint = new TextMarker(e.latlng, "BP", "rgb(37 99 235)", { interactive: true, draggable: true });
|
||||
this.#targetPoint.addTo(this);
|
||||
this.#targetPoint.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
});
|
||||
this.#targetPoint.on("dragend", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
event.target.options["freeze"] = false;
|
||||
});
|
||||
this.#targetPoint.on("click", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
});
|
||||
} else this.#targetPoint.setLatLng(e.latlng);
|
||||
} else if (getApp().getSubState() === JTACSubState.SELECT_ECHO_POINT) {
|
||||
if (!this.#ECHOPoint) {
|
||||
this.#ECHOPoint = new TextMarker(e.latlng, "BP", "rgb(37 99 235)", { interactive: true, draggable: true });
|
||||
this.#ECHOPoint.addTo(this);
|
||||
this.#ECHOPoint.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
});
|
||||
this.#ECHOPoint.on("dragend", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
event.target.options["freeze"] = false;
|
||||
});
|
||||
this.#ECHOPoint.on("click", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
});
|
||||
} else this.#ECHOPoint.setLatLng(e.latlng);
|
||||
} else if (getApp().getSubState() === JTACSubState.SELECT_IP) {
|
||||
if (!this.#IPPoint) {
|
||||
this.#IPPoint = new TextMarker(e.latlng, "BP", "rgb(37 99 235)", { interactive: true, draggable: true });
|
||||
this.#IPPoint.addTo(this);
|
||||
this.#IPPoint.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
});
|
||||
this.#IPPoint.on("dragend", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
event.target.options["freeze"] = false;
|
||||
});
|
||||
this.#IPPoint.on("click", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
});
|
||||
} else this.#IPPoint.setLatLng(e.latlng);
|
||||
}
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
this.#drawIPToTargetLine();
|
||||
} else if (getApp().getState() === OlympusState.UNIT_CONTROL) {
|
||||
if (this.#contextAction !== null) this.executeContextAction(null, e.latlng, e.originalEvent);
|
||||
else if (getApp().getSubState() === NO_SUBSTATE) getApp().setState(OlympusState.IDLE);
|
||||
else getApp().setState(OlympusState.UNIT_CONTROL);
|
||||
} else if (getApp().getState() === OlympusState.MEASURE) {
|
||||
const newMeasure = new Measure(this);
|
||||
const previousMeasure = this.#measures[this.#measures.length - 1];
|
||||
this.#measures.push(newMeasure);
|
||||
newMeasure.onClick(e.latlng);
|
||||
if (previousMeasure && previousMeasure.isActive()) {
|
||||
previousMeasure.finish();
|
||||
previousMeasure.hideEndMarker();
|
||||
newMeasure.onMarkerMoved = (startLatLng, endLatLng) => {
|
||||
previousMeasure.moveMarkers(null, startLatLng);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (getApp().getSubState() === NO_SUBSTATE) getApp().setState(OlympusState.IDLE);
|
||||
else getApp().setState(OlympusState.UNIT_CONTROL);
|
||||
this.addExplosionMarker(e.latlng);
|
||||
} else if (this.#effectRequestTable.type === "smoke") {
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.spawnSmoke(this.#effectRequestTable.smokeColor ?? "white", e.latlng);
|
||||
this.addSmokeMarker(e.latlng, this.#effectRequestTable.smokeColor ?? "white");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.#debounceTimeout) window.clearTimeout(this.#debounceTimeout);
|
||||
this.#debounceTimeout = null;
|
||||
}, DEBOUNCE_MILLISECONDS);
|
||||
}
|
||||
} else if (getApp().getState() === OlympusState.DRAW) {
|
||||
getApp().getCoalitionAreasManager().onLeftShortClick(e);
|
||||
} else if (getApp().getState() === OlympusState.JTAC) {
|
||||
// TODO less redundant way to do this
|
||||
if (getApp().getSubState() === JTACSubState.SELECT_TARGET) {
|
||||
if (!this.#targetPoint) {
|
||||
this.#targetPoint = new TextMarker(e.latlng, "BP", "rgb(37 99 235)", { interactive: true, draggable: true });
|
||||
this.#targetPoint.addTo(this);
|
||||
this.#targetPoint.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
});
|
||||
this.#targetPoint.on("dragend", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
event.target.options["freeze"] = false;
|
||||
});
|
||||
this.#targetPoint.on("click", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
});
|
||||
} else this.#targetPoint.setLatLng(e.latlng);
|
||||
} else if (getApp().getSubState() === JTACSubState.SELECT_ECHO_POINT) {
|
||||
if (!this.#ECHOPoint) {
|
||||
this.#ECHOPoint = new TextMarker(e.latlng, "BP", "rgb(37 99 235)", { interactive: true, draggable: true });
|
||||
this.#ECHOPoint.addTo(this);
|
||||
this.#ECHOPoint.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
});
|
||||
this.#ECHOPoint.on("dragend", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
event.target.options["freeze"] = false;
|
||||
});
|
||||
this.#ECHOPoint.on("click", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
});
|
||||
} else this.#ECHOPoint.setLatLng(e.latlng);
|
||||
} else if (getApp().getSubState() === JTACSubState.SELECT_IP) {
|
||||
if (!this.#IPPoint) {
|
||||
this.#IPPoint = new TextMarker(e.latlng, "BP", "rgb(37 99 235)", { interactive: true, draggable: true });
|
||||
this.#IPPoint.addTo(this);
|
||||
this.#IPPoint.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
});
|
||||
this.#IPPoint.on("dragend", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
event.target.options["freeze"] = false;
|
||||
});
|
||||
this.#IPPoint.on("click", (event) => {
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
});
|
||||
} else this.#IPPoint.setLatLng(e.latlng);
|
||||
}
|
||||
getApp().setState(OlympusState.JTAC);
|
||||
this.#drawIPToTargetLine();
|
||||
} else if (getApp().getState() === OlympusState.UNIT_CONTROL) {
|
||||
if (this.#contextAction !== null) this.executeContextAction(null, e.latlng, e.originalEvent);
|
||||
else if (getApp().getSubState() === NO_SUBSTATE) getApp().setState(OlympusState.IDLE);
|
||||
else getApp().setState(OlympusState.UNIT_CONTROL);
|
||||
} else if (getApp().getState() === OlympusState.MEASURE) {
|
||||
const newMeasure = new Measure(this);
|
||||
const previousMeasure = this.#measures[this.#measures.length - 1];
|
||||
this.#measures.push(newMeasure);
|
||||
newMeasure.onClick(e.latlng);
|
||||
if (previousMeasure && previousMeasure.isActive()) {
|
||||
previousMeasure.finish();
|
||||
previousMeasure.hideEndMarker();
|
||||
newMeasure.onMarkerMoved = (startLatLng, endLatLng) => {
|
||||
previousMeasure.moveMarkers(null, startLatLng);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (getApp().getSubState() === NO_SUBSTATE) getApp().setState(OlympusState.IDLE);
|
||||
else getApp().setState(OlympusState.UNIT_CONTROL);
|
||||
}
|
||||
}
|
||||
|
||||
#onRightShortClick(e: L.LeafletMouseEvent) {
|
||||
console.log(`Right short click at ${e.latlng}`);
|
||||
#onLeftMouseLongClick(e: any) {
|
||||
if (this.#isDragging || this.#isSelecting) return;
|
||||
console.log(`Left long click at ${e.latlng}`);
|
||||
|
||||
window.clearTimeout(this.#rightMouseDownTimeout);
|
||||
if (getApp().getState() === OlympusState.UNIT_CONTROL) {
|
||||
if (!this.getContextAction()) {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.MAP_CONTEXT_MENU);
|
||||
MapContextMenuRequestEvent.dispatch(e.latlng);
|
||||
} else {
|
||||
this.#destinationRotationCenter = e.latlng;
|
||||
this.#isRotatingDestination = true;
|
||||
this.setKeepRelativePositions(true);
|
||||
this.dragging.disable();
|
||||
}
|
||||
} else {
|
||||
getApp().setState(OlympusState.IDLE);
|
||||
this.setSelectionEnabled(true);
|
||||
|
||||
//@ts-ignore We force the boxselect to enter in selection mode
|
||||
this.boxSelect._onMouseDown(e.originalEvent);
|
||||
}
|
||||
}
|
||||
|
||||
#onRightMouseShortClick(e: L.LeafletMouseEvent) {
|
||||
console.log(`Right short click at ${e.latlng}`);
|
||||
|
||||
if (getApp().getState() === OlympusState.IDLE || getApp().getState() === OlympusState.SPAWN_CONTEXT) {
|
||||
SpawnContextMenuRequestEvent.dispatch(e.latlng);
|
||||
@ -1180,22 +1192,17 @@ export class Map extends L.Map {
|
||||
}
|
||||
}
|
||||
|
||||
#onRightLongClick(e: L.LeafletMouseEvent) {
|
||||
#onRightMouseLongClick(e: L.LeafletMouseEvent) {
|
||||
console.log(`Right long click at ${e.latlng}`);
|
||||
|
||||
if (getApp().getState() === OlympusState.UNIT_CONTROL) {
|
||||
if (!this.getContextAction()) {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.MAP_CONTEXT_MENU);
|
||||
MapContextMenuRequestEvent.dispatch(e.latlng);
|
||||
}
|
||||
}
|
||||
this.#destinationRotationCenter = e.latlng;
|
||||
this.#isRotatingDestination = true;
|
||||
this.setKeepRelativePositions(true);
|
||||
}
|
||||
|
||||
#onDoubleClick(e: L.LeafletMouseEvent) {
|
||||
#onLeftMouseDoubleClick(e: L.LeafletMouseEvent) {
|
||||
console.log(`Double click at ${e.latlng}`);
|
||||
|
||||
if (this.#debounceTimeout) window.clearTimeout(this.#debounceTimeout);
|
||||
|
||||
this.setPasteEnabled(false);
|
||||
|
||||
if (getApp().getState() === OlympusState.DRAW) {
|
||||
@ -1211,7 +1218,6 @@ export class Map extends L.Map {
|
||||
|
||||
#onMouseMove(e: any) {
|
||||
if (!this.#isRotatingDestination) {
|
||||
this.#destionationWasRotated = false;
|
||||
this.#lastMousePosition.x = e.originalEvent.x;
|
||||
this.#lastMousePosition.y = e.originalEvent.y;
|
||||
this.#lastMouseCoordinates = e.latlng;
|
||||
@ -1225,18 +1231,33 @@ export class Map extends L.Map {
|
||||
if (this.#currentSpawnMarker) this.#currentSpawnMarker.setLatLng(e.latlng);
|
||||
if (this.#currentEffectMarker) this.#currentEffectMarker.setLatLng(e.latlng);
|
||||
} else if (getApp().getState() === OlympusState.MEASURE) {
|
||||
if (this.#debounceTimeout === null) {
|
||||
this.#measures[this.#measures.length - 1]?.onMouseMove(e.latlng);
|
||||
let totalLength = 0;
|
||||
this.#measures.forEach((measure) => {
|
||||
measure.setTotalDistance(totalLength);
|
||||
totalLength += measure.getDistance();
|
||||
});
|
||||
}
|
||||
//if (this.#debounceTimeout === null) {
|
||||
this.#measures[this.#measures.length - 1]?.onMouseMove(e.latlng);
|
||||
let totalLength = 0;
|
||||
this.#measures.forEach((measure) => {
|
||||
measure.setTotalDistance(totalLength);
|
||||
totalLength += measure.getDistance();
|
||||
});
|
||||
//}
|
||||
}
|
||||
} else {
|
||||
this.#destionationWasRotated = true;
|
||||
this.#destinationRotation -= e.originalEvent.movementX;
|
||||
if (this.#destinationRotationCenter) {
|
||||
/* Compute the average heading of the units */
|
||||
const selectedUnits = getApp()
|
||||
.getUnitsManager()
|
||||
.getSelectedUnits()
|
||||
.filter((unit) => !unit.getHuman());
|
||||
|
||||
let averageHeading = 0;
|
||||
selectedUnits.forEach((unit) => {
|
||||
averageHeading += unit.getHeading();
|
||||
});
|
||||
averageHeading /= selectedUnits.length;
|
||||
|
||||
/* Compute the rotation of the destination */
|
||||
let angle = Math.atan2(e.latlng.lng - this.#destinationRotationCenter.lng, e.latlng.lat - this.#destinationRotationCenter.lat);
|
||||
this.#destinationRotation = -(rad2deg(angle) - getMagvar(e.latlng.lat, e.latlng.lng) - rad2deg(averageHeading));
|
||||
}
|
||||
}
|
||||
|
||||
if (getApp().getState() === OlympusState.DRAW && (getApp().getSubState() === DrawSubState.NO_SUBSTATE || getApp().getSubState() === DrawSubState.EDIT)) {
|
||||
@ -1345,7 +1366,7 @@ export class Map extends L.Map {
|
||||
|
||||
#moveDestinationPreviewMarkers() {
|
||||
if (this.#keepRelativePositions) {
|
||||
Object.entries(getApp().getUnitsManager().computeGroupDestination(this.#lastMouseCoordinates, this.#destinationRotation)).forEach(([ID, latlng]) => {
|
||||
Object.entries(getApp().getUnitsManager().computeGroupDestination(this.#destinationRotationCenter, this.#destinationRotation)).forEach(([ID, latlng]) => {
|
||||
this.#destinationPreviewMarkers[ID]?.setLatLng(latlng);
|
||||
});
|
||||
} else {
|
||||
|
||||
198
frontend/react/src/map/mapMouseHandler.ts
Normal file
198
frontend/react/src/map/mapMouseHandler.ts
Normal file
@ -0,0 +1,198 @@
|
||||
import { DomEvent, LeafletMouseEvent, Point } from "leaflet";
|
||||
import { Map } from "./map";
|
||||
|
||||
enum MapMouseHandlerState {
|
||||
IDLE = "IDLE",
|
||||
LEFT_MOUSE_DOWN = "Left mouse down",
|
||||
MOUSE_WHEEL_DOWN = "Mouse wheel down",
|
||||
RIGHT_MOUSE_DOWN = "Right mouse down",
|
||||
DEBOUNCING = "Debouncing",
|
||||
}
|
||||
|
||||
export class MapMouseHandler {
|
||||
#map: Map;
|
||||
#state: string = MapMouseHandlerState.IDLE;
|
||||
#leftMouseDownEpoch: number = 0;
|
||||
#rightMouseDownEpoch: number = 0;
|
||||
#mouseWheelDownEpoch: number = 0;
|
||||
#leftMouseDownTimeout: number | null = null;
|
||||
#rightMouseDownTimeout: number | null = null;
|
||||
#mouseWheelDownTimeout: number | null = null;
|
||||
|
||||
#debounceTimeout: number | null = null;
|
||||
|
||||
leftMousePressed: (event: LeafletMouseEvent) => void = () => {};
|
||||
leftMouseReleased: (event: LeafletMouseEvent) => void = () => {};
|
||||
rightMousePressed: (event: LeafletMouseEvent) => void = () => {};
|
||||
rightMouseReleased: (event: LeafletMouseEvent) => void = () => {};
|
||||
mouseWheelPressed: (event: LeafletMouseEvent) => void = () => {};
|
||||
mouseWheelReleased: (event: LeafletMouseEvent) => void = () => {};
|
||||
|
||||
leftMouseDoubleClick: (event: LeafletMouseEvent) => void = () => {};
|
||||
|
||||
leftMouseShortClick: (event: LeafletMouseEvent) => void = () => {};
|
||||
rightMouseShortClick: (event: LeafletMouseEvent) => void = () => {};
|
||||
mouseWheelShortClick: (event: LeafletMouseEvent) => void = () => {};
|
||||
leftMouseLongClick: (event: LeafletMouseEvent) => void = () => {};
|
||||
rightMouseLongClick: (event: LeafletMouseEvent) => void = () => {};
|
||||
mouseWheelLongClick: (event: LeafletMouseEvent) => void = () => {};
|
||||
|
||||
mouseMove: (event: LeafletMouseEvent) => void = () => {};
|
||||
|
||||
mouseWheel: (event: LeafletMouseEvent) => void = () => {};
|
||||
|
||||
constructor(map) {
|
||||
this.#map = map;
|
||||
|
||||
/* Events for touchscreen and mouse */
|
||||
if ("ontouchstart" in window) {
|
||||
DomEvent.on(this.#map.getContainer(), "touchstart", (e: any) => this.#onTouchDown(e), this);
|
||||
DomEvent.on(this.#map.getContainer(), "touchend", (e: any) => this.#onTouchUp(e), this);
|
||||
DomEvent.on(this.#map.getContainer(), "touchmove", (e: any) => this.#onTouchMove(e), this);
|
||||
} else {
|
||||
this.#map.on("mouseup", (e: any) => this.#onMouseUp(e));
|
||||
this.#map.on("mousedown", (e: any) => this.#onMouseDown(e));
|
||||
this.#map.on("mousemove", (e: any) => this.#onMouseMove(e));
|
||||
}
|
||||
this.#map.on("dblclick", (e: any) => this.#onDoubleClick(e));
|
||||
|
||||
/* Disable unwanted events */
|
||||
this.#map.on("click", (e: any) => e.originalEvent.preventDefault());
|
||||
this.#map.on("contextmenu", (e: any) => e.originalEvent.preventDefault());
|
||||
|
||||
/* Mouse wheel event */
|
||||
DomEvent.on(this.#map.getContainer(), "wheel", (e: any) => this.#onMouseWheel(e), this);
|
||||
}
|
||||
|
||||
setState(state: string) {
|
||||
console.log("MouseHandler switching state from", this.#state, "to", state);
|
||||
this.#state = state;
|
||||
}
|
||||
|
||||
#onMouseDown = (e: LeafletMouseEvent) => {
|
||||
if (e.originalEvent.button === 0) {
|
||||
this.leftMousePressed(e);
|
||||
this.setState(MapMouseHandlerState.LEFT_MOUSE_DOWN);
|
||||
this.#leftMouseDownEpoch = Date.now();
|
||||
this.#leftMouseDownTimeout = window.setTimeout(() => {
|
||||
this.leftMouseLongClick(e);
|
||||
this.#leftMouseDownTimeout = null;
|
||||
}, 300);
|
||||
} else if (e.originalEvent.button === 1) {
|
||||
this.mouseWheelPressed(e);
|
||||
this.setState(MapMouseHandlerState.MOUSE_WHEEL_DOWN);
|
||||
this.#mouseWheelDownEpoch = Date.now();
|
||||
this.#mouseWheelDownTimeout = window.setTimeout(() => {
|
||||
this.mouseWheelLongClick(e);
|
||||
this.#mouseWheelDownTimeout = null;
|
||||
}, 300);
|
||||
} else if (e.originalEvent.button === 2) {
|
||||
this.rightMousePressed(e);
|
||||
this.setState(MapMouseHandlerState.RIGHT_MOUSE_DOWN);
|
||||
this.#rightMouseDownEpoch = Date.now();
|
||||
this.#rightMouseDownTimeout = window.setTimeout(() => {
|
||||
this.rightMouseLongClick(e);
|
||||
this.#rightMouseDownTimeout = null;
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
||||
#onMouseUp = (e: LeafletMouseEvent) => {
|
||||
if (this.#leftMouseDownTimeout) {
|
||||
clearTimeout(this.#leftMouseDownTimeout);
|
||||
this.#leftMouseDownTimeout = null;
|
||||
}
|
||||
if (this.#rightMouseDownTimeout) {
|
||||
clearTimeout(this.#rightMouseDownTimeout);
|
||||
this.#rightMouseDownTimeout = null;
|
||||
}
|
||||
if (this.#rightMouseDownTimeout) {
|
||||
clearTimeout(this.#rightMouseDownTimeout);
|
||||
this.#rightMouseDownTimeout = null;
|
||||
}
|
||||
|
||||
if (this.#state === MapMouseHandlerState.LEFT_MOUSE_DOWN) {
|
||||
this.leftMouseReleased(e);
|
||||
if (Date.now() - this.#leftMouseDownEpoch < 300) {
|
||||
this.setState(MapMouseHandlerState.DEBOUNCING);
|
||||
this.#debounceTimeout = window.setTimeout(() => {
|
||||
this.leftMouseShortClick(e);
|
||||
}, 300);
|
||||
}
|
||||
} else if (this.#state === MapMouseHandlerState.MOUSE_WHEEL_DOWN) {
|
||||
this.mouseWheelReleased(e);
|
||||
if (Date.now() - this.#mouseWheelDownEpoch < 300) {
|
||||
this.mouseWheelShortClick(e);
|
||||
}
|
||||
} else if (this.#state === MapMouseHandlerState.RIGHT_MOUSE_DOWN) {
|
||||
this.rightMouseReleased(e);
|
||||
if (Date.now() - this.#rightMouseDownEpoch < 300) {
|
||||
this.rightMouseShortClick(e);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState(MapMouseHandlerState.IDLE);
|
||||
};
|
||||
|
||||
#onDoubleClick = (e: LeafletMouseEvent) => {
|
||||
this.leftMouseDoubleClick(e);
|
||||
if (this.#debounceTimeout) {
|
||||
clearTimeout(this.#debounceTimeout);
|
||||
}
|
||||
};
|
||||
|
||||
#onMouseWheel = (e: LeafletMouseEvent) => {
|
||||
this.mouseWheel(e);
|
||||
};
|
||||
|
||||
#onTouchDown = (e: TouchEvent) => {
|
||||
let newEvent = {
|
||||
latlng: this.#map.containerPointToLatLng(this.#map.mouseEventToContainerPoint(e.changedTouches[0] as unknown as MouseEvent)),
|
||||
originalEvent: e,
|
||||
} as unknown as LeafletMouseEvent;
|
||||
|
||||
this.leftMousePressed(newEvent);
|
||||
this.setState(MapMouseHandlerState.LEFT_MOUSE_DOWN);
|
||||
this.#leftMouseDownEpoch = Date.now();
|
||||
this.#leftMouseDownTimeout = window.setTimeout(() => {
|
||||
this.leftMouseLongClick(newEvent);
|
||||
this.#leftMouseDownTimeout = null;
|
||||
}, 300);
|
||||
};
|
||||
|
||||
#onTouchUp = (e: TouchEvent) => {
|
||||
let newEvent = {
|
||||
latlng: this.#map.containerPointToLatLng(this.#map.mouseEventToContainerPoint(e.changedTouches[0] as unknown as MouseEvent)),
|
||||
originalEvent: e,
|
||||
} as unknown as LeafletMouseEvent;
|
||||
|
||||
if (this.#leftMouseDownTimeout) {
|
||||
clearTimeout(this.#leftMouseDownTimeout);
|
||||
this.#leftMouseDownTimeout = null;
|
||||
}
|
||||
|
||||
if (this.#state === MapMouseHandlerState.LEFT_MOUSE_DOWN) {
|
||||
this.leftMouseReleased(newEvent);
|
||||
if (Date.now() - this.#leftMouseDownEpoch < 300) {
|
||||
this.#debounceTimeout = window.setTimeout(() => {
|
||||
this.leftMouseShortClick(newEvent);
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState(MapMouseHandlerState.IDLE);
|
||||
};
|
||||
|
||||
#onMouseMove = (e: LeafletMouseEvent) => {
|
||||
this.mouseMove(e);
|
||||
};
|
||||
|
||||
#onTouchMove = (e: TouchEvent) => {
|
||||
let newEvent = {
|
||||
latlng: this.#map.containerPointToLatLng(this.#map.mouseEventToContainerPoint(e.changedTouches[0] as unknown as MouseEvent)),
|
||||
originalEvent: e,
|
||||
} as unknown as LeafletMouseEvent;
|
||||
|
||||
this.mouseMove(newEvent);
|
||||
};
|
||||
}
|
||||
@ -22,6 +22,10 @@ export function bearing(lat1: number, lon1: number, lat2: number, lon2: number,
|
||||
return brng;
|
||||
}
|
||||
|
||||
export function getMagvar(lat: number, lon: number) {
|
||||
return MagVar.get(lat, lon);
|
||||
}
|
||||
|
||||
export function distance(lat1: number, lon1: number, lat2: number, lon2: number) {
|
||||
const R = 6371e3; // metres
|
||||
const φ1 = deg2rad(lat1); // φ, λ in radians
|
||||
|
||||
@ -121,6 +121,7 @@ export class ServerManager {
|
||||
/* If provided, set the credentials */
|
||||
xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${this.#username ?? ""}:${this.#password ?? ""}`));
|
||||
xmlHttp.setRequestHeader("X-Command-Mode", this.#activeCommandMode);
|
||||
xmlHttp.timeout = 2000;
|
||||
|
||||
/* If specified, set the response type */
|
||||
if (responseType) xmlHttp.responseType = responseType as XMLHttpRequestResponseType;
|
||||
@ -215,7 +216,7 @@ export class ServerManager {
|
||||
}
|
||||
|
||||
getUnits(callback: CallableFunction, refresh: boolean = false, errorCallback: CallableFunction = () => {}) {
|
||||
this.GET(callback, errorCallback, UNITS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] }, "arraybuffer", false);
|
||||
this.GET(callback, errorCallback, UNITS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] }, "arraybuffer", refresh);
|
||||
}
|
||||
|
||||
getWeapons(callback: CallableFunction, refresh: boolean = false, errorCallback: CallableFunction = () => {}) {
|
||||
|
||||
@ -37,12 +37,14 @@ export function MapContextMenu(props: {}) {
|
||||
});
|
||||
ContextActionSetChangedEvent.on((contextActionSet) => setcontextActionSet(contextActionSet));
|
||||
MapContextMenuRequestEvent.on((latlng) => {
|
||||
setUnit(null);
|
||||
setLatLng(latlng);
|
||||
const containerPoint = getApp().getMap().latLngToContainerPoint(latlng);
|
||||
setXPosition(getApp().getMap().getContainer().offsetLeft + containerPoint.x);
|
||||
setYPosition(getApp().getMap().getContainer().offsetTop + containerPoint.y);
|
||||
});
|
||||
UnitContextMenuRequestEvent.on((unit) => {
|
||||
setLatLng(null);
|
||||
setUnit(unit);
|
||||
const containerPoint = getApp().getMap().latLngToContainerPoint(unit.getPosition());
|
||||
setXPosition(getApp().getMap().getContainer().offsetLeft + containerPoint.x);
|
||||
@ -100,8 +102,8 @@ export function MapContextMenu(props: {}) {
|
||||
<div
|
||||
ref={contentRef}
|
||||
className={`
|
||||
absolute flex min-w-80 gap-2 rounded-md bg-olympus-600
|
||||
`}
|
||||
absolute flex min-w-80 gap-2 rounded-md bg-olympus-600
|
||||
`}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
|
||||
@ -91,14 +91,14 @@ export function ControlsPanel(props: {}) {
|
||||
target: faFighterJet,
|
||||
text: "Show unit actions",
|
||||
});
|
||||
controls.push({
|
||||
actions: shortcuts["toggleRelativePositions"]?.toActions(),
|
||||
text: "Activate group movement",
|
||||
});
|
||||
controls.push({
|
||||
actions: [...shortcuts["toggleRelativePositions"]?.toActions(), "Wheel"],
|
||||
text: "Rotate formation",
|
||||
});
|
||||
//controls.push({
|
||||
// actions: shortcuts["toggleRelativePositions"]?.toActions(),
|
||||
// text: "Activate group movement",
|
||||
//});
|
||||
//controls.push({
|
||||
// actions: [...shortcuts["toggleRelativePositions"]?.toActions(), "Wheel"],
|
||||
// text: "Rotate formation",
|
||||
//});
|
||||
} else if (appState === OlympusState.SPAWN) {
|
||||
controls = [
|
||||
{
|
||||
|
||||
@ -21,9 +21,10 @@ export function InfoBar(props: {}) {
|
||||
<div
|
||||
key={idx}
|
||||
className={`
|
||||
absolute w-fit translate-x-[-50%] gap-2 text-nowrap rounded-full
|
||||
absolute w-[250px] translate-x-[-50%] gap-2 rounded-full
|
||||
bg-olympus-800/90 px-4 py-2 text-center text-sm text-white
|
||||
shadow-md backdrop-blur-lg backdrop-grayscale
|
||||
sm:w-fit sm:text-nowrap
|
||||
`}
|
||||
style={{ top: `${idx * 20}px` }}
|
||||
>
|
||||
|
||||
@ -140,12 +140,16 @@ export function MapToolBar(props: {}) {
|
||||
{!scrolledTop && (
|
||||
<FaChevronUp
|
||||
className={`
|
||||
absolute top-0 h-6 w-full rounded-lg px-3.5 py-1 text-gray-200
|
||||
absolute top-0 h-6 w-full rounded-lg bg-red-500 px-3.5 py-1
|
||||
text-gray-200
|
||||
dark:bg-olympus-900
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
<div className={`flex flex-col gap-2 overflow-y-auto no-scrollbar p-2`} onScroll={(ev) => onScroll(ev.target)} ref={scrollRef}>
|
||||
<div className={`
|
||||
pointer-events-auto flex flex-col gap-2 overflow-y-auto no-scrollbar
|
||||
p-2
|
||||
`} onScroll={(ev) => onScroll(ev.target)} ref={scrollRef}>
|
||||
<>
|
||||
<div className="flex flex-col gap-1">
|
||||
<OlStateButton
|
||||
|
||||
@ -1593,6 +1593,9 @@ export abstract class Unit extends CustomMarker {
|
||||
|
||||
this.#isLeftMouseDown = true;
|
||||
this.#leftMouseDownEpoch = Date.now();
|
||||
this.#leftMouseDownTimeout = window.setTimeout(() => {
|
||||
this.#onLeftLongClick(e);
|
||||
}, SHORT_PRESS_MILLISECONDS);
|
||||
} else if (e.originalEvent?.button === 2) {
|
||||
if (
|
||||
getApp().getState() === OlympusState.IDLE ||
|
||||
@ -1617,6 +1620,8 @@ export abstract class Unit extends CustomMarker {
|
||||
DomEvent.preventDefault(e);
|
||||
e.originalEvent.stopImmediatePropagation();
|
||||
|
||||
window.clearTimeout(this.#leftMouseDownTimeout);
|
||||
|
||||
if (this.#debounceTimeout) window.clearTimeout(this.#debounceTimeout);
|
||||
this.#debounceTimeout = window.setTimeout(() => {
|
||||
console.log(`Left short click on ${this.getUnitName()}`);
|
||||
@ -1631,20 +1636,8 @@ export abstract class Unit extends CustomMarker {
|
||||
}, SHORT_PRESS_MILLISECONDS);
|
||||
}
|
||||
|
||||
#onRightShortClick(e: any) {
|
||||
console.log(`Right short click on ${this.getUnitName()}`);
|
||||
|
||||
window.clearTimeout(this.#rightMouseDownTimeout);
|
||||
if (
|
||||
getApp().getState() === OlympusState.UNIT_CONTROL &&
|
||||
getApp().getMap().getDefaultContextAction() &&
|
||||
getApp().getMap().getDefaultContextAction()?.getTarget() === ContextActionTarget.POINT
|
||||
)
|
||||
getApp().getMap().executeDefaultContextAction(null, this.getPosition(), e.originalEvent);
|
||||
}
|
||||
|
||||
#onRightLongClick(e: any) {
|
||||
console.log(`Right long click on ${this.getUnitName()}`);
|
||||
#onLeftLongClick(e: any) {
|
||||
console.log(`Left long click on ${this.getUnitName()}`);
|
||||
|
||||
if (getApp().getState() === OlympusState.IDLE) {
|
||||
this.setSelected(!this.getSelected());
|
||||
@ -1669,6 +1662,22 @@ export abstract class Unit extends CustomMarker {
|
||||
}
|
||||
}
|
||||
|
||||
#onRightShortClick(e: any) {
|
||||
console.log(`Right short click on ${this.getUnitName()}`);
|
||||
|
||||
window.clearTimeout(this.#rightMouseDownTimeout);
|
||||
if (
|
||||
getApp().getState() === OlympusState.UNIT_CONTROL &&
|
||||
getApp().getMap().getDefaultContextAction() &&
|
||||
getApp().getMap().getDefaultContextAction()?.getTarget() === ContextActionTarget.POINT
|
||||
)
|
||||
getApp().getMap().executeDefaultContextAction(null, this.getPosition(), e.originalEvent);
|
||||
}
|
||||
|
||||
#onRightLongClick(e: any) {
|
||||
console.log(`Right long click on ${this.getUnitName()}`);
|
||||
}
|
||||
|
||||
#onDoubleClick(e: any) {
|
||||
DomEvent.stop(e);
|
||||
DomEvent.preventDefault(e);
|
||||
|
||||
@ -50,7 +50,6 @@ import { UnitDatabase } from "./databases/unitdatabase";
|
||||
import * as turf from "@turf/turf";
|
||||
import { PathMarker } from "../map/markers/pathmarker";
|
||||
import { Coalition } from "../types/types";
|
||||
import { ClusterMarker } from "../map/markers/clustermarker";
|
||||
|
||||
/** The UnitsManager handles the creation, update, and control of units. Data is strictly updated by the server ONLY. This means that any interaction from the user will always and only
|
||||
* result in a command to the server, executed by means of a REST PUT request. Any subsequent change in data will be reflected only when the new data is sent back by the server. This strategy allows
|
||||
@ -340,10 +339,16 @@ export class UnitsManager {
|
||||
pathMarkersCoordinates.forEach((latlng: LatLng) => {
|
||||
if (!this.#pathMarkers.some((pathMarker: PathMarker) => pathMarker.getLatLng().equals(latlng))) {
|
||||
const pathMarker = new PathMarker(latlng);
|
||||
|
||||
pathMarker.on("mousedown", (event) => {
|
||||
DomEvent.stopPropagation(event);
|
||||
});
|
||||
pathMarker.on("mouseup", (event) => {
|
||||
DomEvent.stopPropagation(event);
|
||||
});
|
||||
pathMarker.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
event.target.options["originalPosition"] = event.target.getLatLng();
|
||||
DomEvent.stopPropagation(event);
|
||||
});
|
||||
pathMarker.on("dragend", (event) => {
|
||||
event.target.options["freeze"] = false;
|
||||
@ -355,6 +360,7 @@ export class UnitsManager {
|
||||
getApp().getServerManager().addDestination(unit.ID, path);
|
||||
}
|
||||
});
|
||||
DomEvent.stopPropagation(event);
|
||||
});
|
||||
|
||||
pathMarker.addTo(getApp().getMap());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user