Completed creation of areas

This commit is contained in:
Davide Passoni
2024-08-02 13:17:42 +02:00
parent 86e0e6b3a3
commit a3e92580c2
12 changed files with 406 additions and 90 deletions

View File

@@ -4,6 +4,10 @@ import { CustomMarker } from "../markers/custommarker";
export class CoalitionAreaHandle extends CustomMarker {
constructor(latlng: LatLng) {
super(latlng, { interactive: true, draggable: true });
this.on("add", (e) => {
this.getElement()?.addEventListener("touchstart", (e) => e.stopPropagation());
})
}
createIcon() {

View File

@@ -49,6 +49,10 @@ export class CoalitionCircle extends Circle {
this.#setRadiusHandle();
this.#drawLabel();
});
this.on("remove", () => {
this.#label.removeFrom(this._map);
});
}
setCoalition(coalition: Coalition) {

View File

@@ -6,7 +6,7 @@ import {
Polygon,
PolylineOptions,
DivIcon,
Marker,
Marker
} from "leaflet";
import { getApp } from "../../olympusapp";
import { CoalitionAreaHandle } from "./coalitionareahandle";
@@ -57,6 +57,10 @@ export class CoalitionPolygon extends Polygon {
this.#setMiddleHandles();
this.#drawLabel();
});
this.on("remove", () => {
this.#label.removeFrom(this._map);
});
}
setCoalition(coalition: Coalition) {

View File

@@ -0,0 +1,179 @@
import * as L from "leaflet";
export const initDraggablePath = () => {
//@ts-ignore
L.PathDraggable = L.Draggable.extend({
initialize: function (path) {
this._path = path;
this._canvas = path._map.getRenderer(path) instanceof L.Canvas;
var element = this._canvas
? this._path._map.getRenderer(this._path)._container
: this._path._path;
//@ts-ignore
L.Draggable.prototype.initialize.call(this, element, element, true);
},
_updatePosition: function () {
var e = { originalEvent: this._lastEvent };
this.fire("drag", e);
},
_onDown: function (e) {
var first = e.touches ? e.touches[0] : e;
this._startPoint = new L.Point(first.clientX, first.clientY);
if (
this._canvas &&
!this._path._containsPoint(
this._path._map.mouseEventToLayerPoint(first)
)
) {
return;
}
//@ts-ignore
L.Draggable.prototype._onDown.call(this, e);
e.stopPropagation();
},
});
//@ts-ignore
L.Handler.PathDrag = L.Handler.extend({
initialize: function (path) {
this._path = path;
},
getEvents: function () {
return {
dragstart: this._onDragStart,
drag: this._onDrag,
dragend: this._onDragEnd,
};
},
addHooks: function () {
if (!this._draggable) {
//@ts-ignore
this._draggable = new L.PathDraggable(this._path);
}
this._draggable.on(this.getEvents(), this).enable();
L.DomUtil.addClass(this._draggable._element, "leaflet-path-draggable");
},
removeHooks: function () {
this._draggable.off(this.getEvents(), this).disable();
L.DomUtil.removeClass(this._draggable._element, "leaflet-path-draggable");
},
moved: function () {
return this._draggable && this._draggable._moved;
},
_onDragStart: function () {
this._startPoint = this._draggable._startPoint;
this._path.closePopup().fire("movestart").fire("dragstart");
},
_onDrag: function (e) {
var path = this._path,
event =
e.originalEvent.touches && e.originalEvent.touches.length === 1
? e.originalEvent.touches[0]
: e.originalEvent,
newPoint = L.point(event.clientX, event.clientY),
latlng = path._map.layerPointToLatLng(newPoint);
this._offset = newPoint.subtract(this._startPoint);
this._startPoint = newPoint;
this._path.eachLatLng(this.updateLatLng, this);
path.redraw();
e.latlng = latlng;
e.offset = this._offset;
path.fire("drag", e);
e.latlng = this._path.getCenter
? this._path.getCenter()
: this._path.getLatLng();
path.fire("move", e);
},
_onDragEnd: function (e) {
if (this._path._bounds) this.resetBounds();
this._path.fire("moveend").fire("dragend", e);
},
latLngToLayerPoint: function (latlng) {
// Same as map.latLngToLayerPoint, but without the round().
var projectedPoint = this._path._map.project(L.latLng(latlng));
return projectedPoint._subtract(this._path._map.getPixelOrigin());
},
updateLatLng: function (latlng) {
var oldPoint = this.latLngToLayerPoint(latlng);
oldPoint._add(this._offset);
var newLatLng = this._path._map.layerPointToLatLng(oldPoint);
latlng.lat = newLatLng.lat;
latlng.lng = newLatLng.lng;
},
resetBounds: function () {
//@ts-ignore
this._path._bounds = new L.LatLngBounds();
this._path.eachLatLng(function (latlng) {
this._bounds.extend(latlng);
});
},
});
L.Path.include({
eachLatLng: function (callback, context) {
context = context || this;
var loop = function (latlngs) {
for (var i = 0; i < latlngs.length; i++) {
if (L.Util.isArray(latlngs[i])) loop(latlngs[i]);
else callback.call(context, latlngs[i]);
}
};
loop(this.getLatLngs ? this.getLatLngs() : [this.getLatLng()]);
},
});
L.Path.addInitHook(function () {
//@ts-ignore
this.dragging = new L.Handler.PathDrag(this);
if (this.options.draggable) {
this.once("add", function () {
this.dragging.enable();
});
}
});
};

View File

@@ -3,13 +3,7 @@ import { getApp } from "../olympusapp";
import { BoxSelect } from "./boxselect";
import { Airbase } from "../mission/airbase";
import { Unit } from "../unit/unit";
import {
areaContains,
circleContains,
deg2rad,
getGroundElevation,
polyContains,
} from "../other/utils";
import { areaContains, deg2rad, getFunctionArguments, getGroundElevation } from "../other/utils";
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
import { ClickableMiniMap } from "./clickableminimap";
import {
@@ -38,12 +32,14 @@ import "./markers/stylesheets/units.css";
import "./map.css";
import { CoalitionCircle } from "./coalitionarea/coalitioncircle";
import "leaflet-path-drag";
import { faLeftLong } from "@fortawesome/free-solid-svg-icons";
import { initDraggablePath } from "./coalitionarea/draggablepath";
import { faDrawPolygon, faJetFighter, faMap } from "@fortawesome/free-solid-svg-icons";
/* Register the handler for the box selection */
L.Map.addInitHook("addHandler", "boxSelect", BoxSelect);
initDraggablePath();
export class Map extends L.Map {
/* Options */
#options: MapOptions = MAP_OPTIONS_DEFAULTS;
@@ -413,63 +409,83 @@ export class Map extends L.Map {
return [
{
actions: ["Tap"],
target: faJetFighter,
text: "Select unit",
},
{
actions: ["Shift", "Drag"],
target: faMap,
text: "Box selection",
},
{
actions: ["Press", "Drag"],
target: faMap,
text: "Box selection",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
{
actions: ["Long tap", "Drag"],
text: "Box selection",
},
];
} else if (this.#state === SPAWN_UNIT) {
return [
{
actions: ["Tap"],
target: faMap,
text: "Spawn unit",
},
{
actions: ["Double tap"],
target: faMap,
text: "Exit spawn mode",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
} else if (this.#state === CONTEXT_ACTION) {
return [
{
actions: ["Tap"],
text: this.#contextAction?.getLabel() ?? "",
},
let controls = [
{
actions: ["Double tap"],
text: "Exit action mode",
target: faMap,
text: "Deselect units",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
if (this.#contextAction) {
/* TODO: I don't like this approach, it relies on the arguments names of the callback. We should find a better method */
const args = getFunctionArguments(this.#contextAction.getCallback());
controls.push({
actions: ["Tap"],
target: args.includes("targetUnit")? faJetFighter: faMap,
text: this.#contextAction?.getLabel() ?? "",
});
}
return controls;
} else if (this.#state === COALITIONAREA_EDIT) {
return [
{
actions: ["Tap"],
target: faDrawPolygon,
text: "Select shape",
},
{
actions: ["Double tap"],
target: faMap,
text: "Exit drawing mode",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
@@ -477,14 +493,17 @@ export class Map extends L.Map {
return [
{
actions: ["Tap"],
target: faMap,
text: "Add vertex to polygon",
},
{
actions: ["Double tap"],
target: faMap,
text: "Finalize polygon",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
@@ -492,10 +511,12 @@ export class Map extends L.Map {
return [
{
actions: ["Tap"],
target: faMap,
text: "Add circle",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
@@ -801,7 +822,8 @@ export class Map extends L.Map {
this.#longPressTimer = window.setTimeout(() => {
/* If the mouse is still being pressed, execute the long press action */
if (this.#isMouseDown) this.#onLongPress(e);
if (this.#isMouseDown && !this.#isDragging && !this.#isZooming)
this.#onLongPress(e);
}, 500);
}
@@ -822,15 +844,20 @@ export class Map extends L.Map {
}
#onShortPress(e: any) {
console.log(`Short press at ${e.latlng}`);
let touchLocation: L.LatLng;
if (e.type === "touchstart")
touchLocation = this.containerPointToLatLng(
this.mouseEventToContainerPoint(e.touches[0])
);
else touchLocation = new L.LatLng(e.latlng.lat, e.latlng.lng);
const location = new L.LatLng(e.latlng.lat, e.latlng.lng);
console.log(`Short press at ${touchLocation}`);
/* Execute the short click action */
if (this.#state === IDLE) {
} else if (this.#state === SPAWN_UNIT) {
if (this.#spawnRequestTable !== null) {
this.#spawnRequestTable.unit.location = location;
this.#spawnRequestTable.unit.location = touchLocation;
getApp()
.getUnitsManager()
.spawnUnits(
@@ -842,7 +869,7 @@ export class Map extends L.Map {
undefined,
(hash) => {
this.addTemporaryMarker(
location,
touchLocation,
this.#spawnRequestTable?.unit.unitType ?? "unknown",
this.#spawnRequestTable?.coalition ?? "blue",
hash
@@ -853,7 +880,7 @@ export class Map extends L.Map {
} else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
const selectedArea = this.getSelectedCoalitionArea();
if (selectedArea && selectedArea instanceof CoalitionPolygon) {
selectedArea.addTemporaryLatLng(location);
selectedArea.addTemporaryLatLng(touchLocation);
}
} else if (this.#state === COALITIONAREA_DRAW_CIRCLE) {
const selectedArea = this.getSelectedCoalitionArea();
@@ -862,13 +889,13 @@ export class Map extends L.Map {
selectedArea.getLatLng().lat == 0 &&
selectedArea.getLatLng().lng == 0
)
selectedArea.setLatLng(location);
selectedArea.setLatLng(touchLocation);
this.setState(COALITIONAREA_EDIT);
}
} else if (this.#state == COALITIONAREA_EDIT) {
this.deselectAllCoalitionAreas();
for (let idx = 0; idx < this.#coalitionAreas.length; idx++) {
if (areaContains(e.latlng, this.#coalitionAreas[idx])) {
if (areaContains(touchLocation, this.#coalitionAreas[idx])) {
this.#coalitionAreas[idx].setSelected(true);
document.dispatchEvent(
new CustomEvent("coalitionAreaSelected", {
@@ -879,18 +906,24 @@ export class Map extends L.Map {
}
}
} else if (this.#state === CONTEXT_ACTION) {
this.executeContextAction(null, e.latlng);
this.executeContextAction(null, touchLocation);
} else {
}
}
#onLongPress(e: any) {
console.log(`Long press at ${e.latlng}`);
let touchLocation: L.LatLng;
if (e.type === "touchstart")
touchLocation = this.containerPointToLatLng(
this.mouseEventToContainerPoint(e.touches[0])
);
else touchLocation = new L.LatLng(e.latlng.lat, e.latlng.lng);
this.deselectAllCoalitionAreas();
console.log(`Long press at ${touchLocation}`);
if (!this.#isDragging && !this.#isZooming) {
if (this.#state == IDLE) {
this.deselectAllCoalitionAreas();
if (this.#state === IDLE) {
if (e.type === "touchstart")
document.dispatchEvent(
new CustomEvent("mapForceBoxSelect", { detail: e })
@@ -908,7 +941,7 @@ export class Map extends L.Map {
this.#lastMousePosition.x = e.originalEvent.x;
this.#lastMousePosition.y = e.originalEvent.y;
this.#lastMouseCoordinates = this.mouseEventToLatLng(e.originalEvent);
this.#lastMouseCoordinates = e.latlng;
}
#onMapMove(e: any) {

View File

@@ -1,9 +1,7 @@
import { Circle, LatLng, Polygon } from "leaflet";
import * as turf from "@turf/turf";
import { UnitDatabase } from "../unit/databases/unitdatabase";
import {
aircraftDatabase,
} from "../unit/databases/aircraftdatabase";
import { aircraftDatabase } from "../unit/databases/aircraftdatabase";
import { helicopterDatabase } from "../unit/databases/helicopterdatabase";
import { groundUnitDatabase } from "../unit/databases/groundunitdatabase";
import {
@@ -317,33 +315,52 @@ export function nmToFt(nm: number) {
}
export function areaContains(latlng: LatLng, area: Polygon | Circle) {
if (area instanceof Polygon)
return polyContains(latlng, area);
else
return circleContains(latlng, area);
if (area instanceof Polygon) return polyContains(latlng, area);
else return circleContains(latlng, area);
}
export function polyContains(latlng: LatLng, polygon: Polygon) {
let coordinates = [(polygon.getLatLngs()[0] as LatLng[]).map((latlng) => {return [latlng.lng, latlng.lat]} )];
coordinates[0].push([polygon.getLatLngs()[0][0].lng, polygon.getLatLngs()[0][0].lat])
let coordinates = [
(polygon.getLatLngs()[0] as LatLng[]).map((latlng) => {
return [latlng.lng, latlng.lat];
}),
];
coordinates[0].push([
polygon.getLatLngs()[0][0].lng,
polygon.getLatLngs()[0][0].lat,
]);
const poly = turf.polygon(coordinates);
return turf.inside(turf.point([latlng.lng, latlng.lat]), poly);
}
export function circleContains(latlng: LatLng, circle: Circle) {
const poly = turf.circle(turf.point([circle.getLatLng().lng, circle.getLatLng().lat]), circle.getRadius() / 1000, 100, 'kilometers');
const poly = turf.circle(
turf.point([circle.getLatLng().lng, circle.getLatLng().lat]),
circle.getRadius() / 1000,
100,
"kilometers"
);
return turf.inside(turf.point([latlng.lng, latlng.lat]), poly);
}
export function polyCenter(polygon: Polygon) {
let coordinates = [(polygon.getLatLngs()[0] as LatLng[]).map((latlng) => {return [latlng.lng, latlng.lat]} )];
coordinates[0].push([polygon.getLatLngs()[0][0].lng, polygon.getLatLngs()[0][0].lat])
let coordinates = [
(polygon.getLatLngs()[0] as LatLng[]).map((latlng) => {
return [latlng.lng, latlng.lat];
}),
];
coordinates[0].push([
polygon.getLatLngs()[0][0].lng,
polygon.getLatLngs()[0][0].lat,
]);
const poly = turf.polygon(coordinates);
const center = turf.center(featureCollection([poly]));
return new LatLng(center.geometry.coordinates[1], center.geometry.coordinates[0]);
return new LatLng(
center.geometry.coordinates[1],
center.geometry.coordinates[0]
);
}
export function randomPointInPoly(polygon: Polygon): LatLng {
var bounds = polygon.getBounds();
var x_min = bounds.getEast();
@@ -354,8 +371,15 @@ export function randomPointInPoly(polygon: Polygon): LatLng {
var lat = y_min + Math.random() * (y_max - y_min);
var lng = x_min + Math.random() * (x_max - x_min);
let coordinates = [(polygon.getLatLngs()[0] as LatLng[]).map((latlng) => {return [latlng.lng, latlng.lat]} )];
coordinates[0].push([polygon.getLatLngs()[0][0].lng, polygon.getLatLngs()[0][0].lat])
let coordinates = [
(polygon.getLatLngs()[0] as LatLng[]).map((latlng) => {
return [latlng.lng, latlng.lat];
}),
];
coordinates[0].push([
polygon.getLatLngs()[0][0].lng,
polygon.getLatLngs()[0][0].lat,
]);
const poly = turf.polygon(coordinates);
var inside = turf.inside(turf.point([lng, lat]), poly);
@@ -565,3 +589,15 @@ export function getWikipediaEntry(search: string, callback: CallableFunction) {
};
xhr.send();
}
export function getFunctionArguments(func) {
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
var ARGUMENT_NAMES = /([^\s,]+)/g;
var fnStr = func.toString().replace(STRIP_COMMENTS, "");
var result = fnStr
.slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")"))
.match(ARGUMENT_NAMES);
if (result === null) result = [];
return result;
}

View File

@@ -1,9 +1,18 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { getApp } from "../../olympusapp";
import { IconDefinition } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export function ControlsPanel(props: {}) {
const [controls, setControls] = useState(
[] as { actions: string[]; text: string }[]
[] as { actions: string[]; target: IconDefinition, text: string }[]
);
useEffect(() => {
if (getApp() && controls.length === 0) {
setControls(getApp().getMap().getCurrentControls());
}
})
document.addEventListener("mapStateChanged", (ev) => {
setControls(getApp().getMap().getCurrentControls());
});
@@ -11,7 +20,7 @@ export function ControlsPanel(props: {}) {
return (
<div
className={`
absolute bottom-[20px] right-[10px] w-[288px] z-ui-0 flex flex-col
absolute bottom-[20px] right-[10px] w-80 z-ui-0 flex flex-col
items-center justify-between gap-1 p-3 text-sm
`}
>
@@ -19,29 +28,32 @@ export function ControlsPanel(props: {}) {
return (
<div
className={`
flex w-full justify-between gap-2 rounded-full px-2 py-1
flex w-full justify-between gap-2 rounded-full py-1 pl-4 pr-2
backdrop-blur-lg
dark:bg-olympus-800/90 dark:text-gray-200
`}
>
<div className="my-auto">{control.text}</div>
<div className="my-auto overflow-hidden text-nowrap">{control.text}</div>
<FontAwesomeIcon icon={control.target} className="my-auto ml-auto"/>
<div className="flex gap-1">
{control.actions.map((action, idx) => {
return (
<>
{<div>+</div>}
<div
className={`
rounded-full bg-olympus-500 px-1 py-0.5 text-sm
rounded-full bg-olympus-500 px-2 py-0.5 text-sm
font-bold text-white
`}
>
{action}
</div>
{idx !== control.actions.length - 1 && <div>+</div>}
</>
);
})}
</div>
</div>
);
})}

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useState } from "react";
import { Menu } from "./components/menu";
import { FaQuestionCircle, FaRegCircle } from "react-icons/fa";
import { FaQuestionCircle, FaRegCircle, FaTrash } from "react-icons/fa";
import { getApp } from "../../olympusapp";
import {
COALITIONAREA_DRAW_CIRCLE,
@@ -62,6 +62,19 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
setAreaCoalition(activeCoalitionArea?.getCoalition());
});
useEffect(() => {
if (!props.open) {
if (
[
COALITIONAREA_EDIT,
COALITIONAREA_DRAW_CIRCLE,
COALITIONAREA_DRAW_POLYGON,
].includes(getApp()?.getMap()?.getState())
)
getApp().getMap().setState(IDLE);
}
});
document.addEventListener("mapStateChanged", (event: any) => {
if (
drawingPolygon &&
@@ -147,7 +160,8 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
Click on the map to add a new circle.
</div>
<div className="text-gray-400">
You can drag the circle to move it and you can use the handle to set the radius.
You can drag the circle to move it and you can use the handle to
set the radius.
</div>
</div>
</div>
@@ -197,11 +211,21 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
text-gray-200
`}
>
<div className="my-auto text-md">Area label </div>
<div className="my-auto flex justify-between text-md">
Area label
<div className="rounded-md bg-red-800 p-2" onClick={() => {
getApp().getMap().deleteCoalitionArea(activeCoalitionArea);
setActiveCoalitionArea(null);
}}>
<FaTrash
className={`text-gray-50`}
></FaTrash>
</div>
</div>
<input
type="text"
className={`
block max-w-80 flex-grow rounded-lg border border-gray-300
block w-full flex-grow rounded-lg border border-gray-300
bg-gray-50 p-2.5 text-sm text-gray-900
dark:border-gray-600 dark:bg-gray-700 dark:text-white
dark:placeholder-gray-400 dark:focus:border-blue-500

View File

@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import {
OlRoundStateButton,
OlStateButton,
@@ -35,10 +35,18 @@ export function Header() {
const [scrolledLeft, setScrolledLeft] = useState(true);
const [scrolledRight, setScrolledRight] = useState(false);
function onScroll(ev) {
const sl = ev.target.scrollLeft;
/* Initialize the "scroll" position of the element */
var scrollRef = useRef(null);
useEffect(() => {
if (scrollRef.current) {
onScroll(scrollRef.current);
}
});
function onScroll(el) {
const sl = el.scrollLeft;
const sr =
ev.target.scrollWidth - ev.target.scrollLeft - ev.target.clientWidth;
el.scrollWidth - el.scrollLeft - el.clientWidth;
sl < 1 && !scrolledLeft && setScrolledLeft(true);
sl > 1 && scrolledLeft && setScrolledLeft(false);
@@ -77,7 +85,8 @@ export function Header() {
my-2 flex w-full items-center gap-3 overflow-x-scroll
no-scrollbar
`}
onScroll={(ev) => onScroll(ev)}
onScroll={(ev) => onScroll(ev.target)}
ref={scrollRef}
>
<div
className={`

View File

@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { Unit } from "../../unit/unit";
import { ContextActionSet } from "../../unit/contextactionset";
import { OlStateButton } from "../components/olstatebutton";
@@ -20,6 +20,14 @@ export function UnitMouseControlBar(props: {}) {
const [scrolledLeft, setScrolledLeft] = useState(true);
const [scrolledRight, setScrolledRight] = useState(false);
/* Initialize the "scroll" position of the element */
var scrollRef = useRef(null);
useEffect(() => {
if (scrollRef.current) {
onScroll(scrollRef.current);
}
});
/* When a unit is selected, open the menu */
document.addEventListener("unitsSelection", (ev: CustomEventInit) => {
setOpen(true);
@@ -61,10 +69,10 @@ export function UnitMouseControlBar(props: {}) {
setActiveContextAction(null);
}
function onScroll(ev) {
const sl = ev.target.scrollLeft;
function onScroll(el) {
const sl = el.scrollLeft;
const sr =
ev.target.scrollWidth - ev.target.scrollLeft - ev.target.clientWidth;
el.scrollWidth - el.scrollLeft - el.clientWidth;
sl < 1 && !scrolledLeft && setScrolledLeft(true);
sl > 1 && scrolledLeft && setScrolledLeft(false);
@@ -96,7 +104,8 @@ export function UnitMouseControlBar(props: {}) {
)}
<div
className="flex gap-2 overflow-x-auto no-scrollbar p-2"
onScroll={(ev) => onScroll(ev)}
onScroll={(ev) => onScroll(ev.target)}
ref={scrollRef}
>
{Object.values(contextActionsSet.getContextActions()).map(
(contextAction) => {

View File

@@ -892,7 +892,7 @@ export abstract class Unit extends CustomMarker {
contextActionSet.addContextAction(
this,
"move",
"Move",
"Set destination",
"Click on the map to move the units there",
faLocationDot,
(units: Unit[], _, targetPosition) => {
@@ -905,7 +905,7 @@ export abstract class Unit extends CustomMarker {
contextActionSet.addContextAction(
this,
"path",
"Path",
"Append destination",
"Click on the map to add a destination to the path",
faRoute,
(units: Unit[], _, targetPosition) => {
@@ -2190,7 +2190,7 @@ export abstract class AirUnit extends Unit {
contextActionSet.addContextAction(
this,
"refuel",
"Refuel",
"Refuel at tanker",
"Refuel units at the nearest AAR Tanker. If no tanker is available the unit will RTB",
olStatesRefuel,
(units: Unit[]) => {
@@ -2220,7 +2220,7 @@ export abstract class AirUnit extends Unit {
(
units: Unit[],
targetUnit: Unit | null,
targetPosition: LatLng | null
_
) => {
if (targetUnit)
getApp().getUnitsManager().attackUnit(targetUnit.ID, units);
@@ -2235,7 +2235,7 @@ export abstract class AirUnit extends Unit {
(
units: Unit[],
targetUnit: Unit | null,
targetPosition: LatLng | null
_
) => {
if (targetUnit) targetUnit.showFollowOptions(units);
}
@@ -2245,12 +2245,12 @@ export abstract class AirUnit extends Unit {
contextActionSet.addContextAction(
this,
"bomb",
"Precision bombing",
"Precision bomb location",
"Click on a point to execute a precision bombing attack",
faLocationCrosshairs,
(
units: Unit[],
targetUnit: Unit | null,
_,
targetPosition: LatLng | null
) => {
if (targetPosition)
@@ -2260,12 +2260,12 @@ export abstract class AirUnit extends Unit {
contextActionSet.addContextAction(
this,
"carpet-bomb",
"Carpet bombing",
"Carpet bomb location",
"Click on a point to execute a carpet bombing attack",
faXmarksLines,
(
units: Unit[],
targetUnit: Unit | null,
_,
targetPosition: LatLng | null
) => {
if (targetPosition)
@@ -2311,12 +2311,12 @@ export class Helicopter extends AirUnit {
contextActionSet.addContextAction(
this,
"land-at-point",
"Land here",
"Land at location",
"Click on a point to land there",
olIconsLandAtPoint,
(
units: Unit[],
targetUnit: Unit | null,
_,
targetPosition: LatLng | null
) => {
if (targetPosition)
@@ -2372,8 +2372,8 @@ export class GroundUnit extends Unit {
faPeopleGroup,
(
units: Unit[],
targetUnit: Unit | null,
targetPosition: LatLng | null
_1,
_2
) => {
getApp().getUnitsManager().createGroup(units);
},
@@ -2426,7 +2426,7 @@ export class GroundUnit extends Unit {
(
units: Unit[],
targetUnit: Unit | null,
targetPosition: LatLng | null
_
) => {
if (targetUnit)
getApp().getUnitsManager().attackUnit(targetUnit.ID, units);
@@ -2443,7 +2443,7 @@ export class GroundUnit extends Unit {
faLocationCrosshairs,
(
units: Unit[],
targetUnit: Unit | null,
_,
targetPosition: LatLng | null
) => {
if (targetPosition)
@@ -2458,7 +2458,7 @@ export class GroundUnit extends Unit {
olButtonsContextSimulateFireFight,
(
units: Unit[],
targetUnit: Unit | null,
_,
targetPosition: LatLng | null
) => {
if (targetPosition)
@@ -2577,8 +2577,8 @@ export class NavyUnit extends Unit {
faQuestionCircle,
(
units: Unit[],
targetUnit: Unit | null,
targetPosition: LatLng | null
_1,
_2
) => {
getApp().getUnitsManager().createGroup(units);
},
@@ -2606,7 +2606,7 @@ export class NavyUnit extends Unit {
(
units: Unit[],
targetUnit: Unit | null,
targetPosition: LatLng | null
_
) => {
if (targetUnit)
getApp().getUnitsManager().attackUnit(targetUnit.ID, units);
@@ -2622,7 +2622,7 @@ export class NavyUnit extends Unit {
faQuestionCircle,
(
units: Unit[],
targetUnit: Unit | null,
_,
targetPosition: LatLng | null
) => {
if (targetPosition)

View File

@@ -20,6 +20,7 @@ import {
import { CoalitionPolygon } from "../map/coalitionarea/coalitionpolygon";
import { groundUnitDatabase } from "./databases/groundunitdatabase";
import {
CONTEXT_ACTION,
DELETE_CYCLE_TIME,
DELETE_SLOW_THRESHOLD,
DataIndexes,
@@ -1953,6 +1954,7 @@ export class UnitsManager {
#onUnitSelection(unit: Unit) {
if (this.getSelectedUnits().length > 0) {
getApp().getMap().setState(CONTEXT_ACTION);
/* Disable the firing of the selection event for a certain amount of time. This avoids firing many events if many units are selected */
if (!this.#selectionEventDisabled) {
window.setTimeout(() => {