mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
More work on coalition areas drawing
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@tanem/svg-injector": "^10.1.68",
|
||||
|
||||
@@ -1,24 +1,31 @@
|
||||
import {
|
||||
DomUtil,
|
||||
LatLng,
|
||||
LatLngExpression,
|
||||
Map,
|
||||
Point,
|
||||
Polygon,
|
||||
PolylineOptions,
|
||||
DivIcon,
|
||||
Marker
|
||||
} from "leaflet";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { CoalitionAreaHandle } from "./coalitionareahandle";
|
||||
import { CoalitionAreaMiddleHandle } from "./coalitionareamiddlehandle";
|
||||
import { BLUE_COMMANDER, RED_COMMANDER } from "../../constants/constants";
|
||||
import { Coalition } from "../../types/types";
|
||||
import { polyCenter } from "../../other/utils";
|
||||
|
||||
export class CoalitionArea extends Polygon {
|
||||
#coalition: string = "blue";
|
||||
let totalAreas = 0;
|
||||
|
||||
export class CoalitionPolygon extends Polygon {
|
||||
#coalition: Coalition = "blue";
|
||||
#selected: boolean = true;
|
||||
#editing: boolean = true;
|
||||
#handles: CoalitionAreaHandle[] = [];
|
||||
#middleHandles: CoalitionAreaMiddleHandle[] = [];
|
||||
#activeIndex: number = 0;
|
||||
#labelText: string;
|
||||
#label: Marker;
|
||||
|
||||
constructor(
|
||||
latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][],
|
||||
@@ -26,12 +33,16 @@ export class CoalitionArea extends Polygon {
|
||||
) {
|
||||
if (options === undefined) options = {};
|
||||
|
||||
totalAreas++;
|
||||
|
||||
options.bubblingMouseEvents = false;
|
||||
options.interactive = false;
|
||||
|
||||
super(latlngs, options);
|
||||
this.#setColors();
|
||||
|
||||
this.#labelText = `Polygon ${totalAreas}`
|
||||
|
||||
if (
|
||||
[BLUE_COMMANDER, RED_COMMANDER].includes(
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode
|
||||
@@ -40,7 +51,7 @@ export class CoalitionArea extends Polygon {
|
||||
this.setCoalition(getApp().getMissionManager().getCommandedCoalition());
|
||||
}
|
||||
|
||||
setCoalition(coalition: string) {
|
||||
setCoalition(coalition: Coalition) {
|
||||
this.#coalition = coalition;
|
||||
this.#setColors();
|
||||
}
|
||||
@@ -53,6 +64,7 @@ export class CoalitionArea extends Polygon {
|
||||
this.#selected = selected;
|
||||
this.#setColors();
|
||||
this.#setHandles();
|
||||
this.#drawLabel();
|
||||
this.setOpacity(selected ? 1 : 0.5);
|
||||
if (!this.getSelected() && this.getEditing()) {
|
||||
/* Remove the vertex we were working on */
|
||||
@@ -88,16 +100,18 @@ export class CoalitionArea extends Polygon {
|
||||
this.#setHandles();
|
||||
}
|
||||
|
||||
moveActiveVertex(latlng: LatLng) {
|
||||
var latlngs = this.getLatLngs()[0] as LatLng[];
|
||||
latlngs[this.#activeIndex] = latlng;
|
||||
this.setLatLngs(latlngs);
|
||||
this.#setHandles();
|
||||
}
|
||||
|
||||
setOpacity(opacity: number) {
|
||||
this.setStyle({ opacity: opacity, fillOpacity: opacity * 0.25 });
|
||||
}
|
||||
|
||||
getLabelText() {
|
||||
return this.#labelText;
|
||||
}
|
||||
|
||||
setLabelText(labelText: string) {
|
||||
this.#labelText = labelText;
|
||||
this.#drawLabel();
|
||||
}
|
||||
|
||||
onRemove(map: Map): this {
|
||||
super.onRemove(map);
|
||||
@@ -109,6 +123,12 @@ export class CoalitionArea extends Polygon {
|
||||
return this;
|
||||
}
|
||||
|
||||
setLatLngs(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]){
|
||||
super.setLatLngs(latlngs);
|
||||
this.#drawLabel();
|
||||
return this;
|
||||
}
|
||||
|
||||
#setColors() {
|
||||
const coalitionColor =
|
||||
this.getCoalition() === "blue" ? "#247be2" : "#ff5858";
|
||||
@@ -165,6 +185,7 @@ export class CoalitionArea extends Polygon {
|
||||
const middleHandle = new CoalitionAreaMiddleHandle(middleLatLng);
|
||||
middleHandle.addTo(getApp().getMap());
|
||||
middleHandle.on("click", (e: any) => {
|
||||
getApp().getMap().preventClicks();
|
||||
this.#activeIndex = idx - 1;
|
||||
this.addTemporaryLatLng(middleLatLng);
|
||||
});
|
||||
@@ -174,4 +195,19 @@ export class CoalitionArea extends Polygon {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#drawLabel() {
|
||||
if (this.#label) {
|
||||
this.#label.removeFrom(this._map);
|
||||
}
|
||||
this.#label = new Marker(polyCenter(this), {
|
||||
icon: new DivIcon({
|
||||
className: 'label',
|
||||
html: this.#labelText,
|
||||
iconSize: [100, 40]
|
||||
}),
|
||||
interactive: false
|
||||
}).addTo(this._map);
|
||||
this.#label.getElement()?.classList.add(`ol-coalitionarea-label`, `${this.#selected? "selected": `${this.#coalition}`}`);
|
||||
}
|
||||
}
|
||||
@@ -105,16 +105,28 @@
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.ol-coalitionarea-handle-icon {
|
||||
.ol-coalitionarea-middle-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;
|
||||
.ol-coalitionarea-label {
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.ol-coalitionarea-label.selected {
|
||||
color: white;
|
||||
/* 1 pixel black shadow to left, top, right and bottom */
|
||||
text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
|
||||
}
|
||||
|
||||
.ol-coalitionarea-label.blue {
|
||||
color: #0f3764;
|
||||
}
|
||||
|
||||
.ol-coalitionarea-label.red {
|
||||
color: #461818;
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
MAP_HIDDEN_TYPES_DEFAULTS,
|
||||
COALITIONAREA_EDIT,
|
||||
} from "../constants/constants";
|
||||
import { CoalitionArea } from "./coalitionarea/coalitionarea";
|
||||
import { CoalitionPolygon } from "./coalitionarea/coalitionpolygon";
|
||||
import { MapHiddenTypes, MapOptions } from "../types/types";
|
||||
import { SpawnRequestTable } from "../interfaces";
|
||||
import { ContextAction } from "../unit/contextaction";
|
||||
@@ -30,6 +30,7 @@ import "./markers/stylesheets/bullseye.css";
|
||||
import "./markers/stylesheets/units.css";
|
||||
import "./map.css";
|
||||
|
||||
/* Register the handler for the box selection */
|
||||
L.Map.addInitHook("addHandler", "boxSelect", BoxSelect);
|
||||
|
||||
export class Map extends L.Map {
|
||||
@@ -91,7 +92,7 @@ export class Map extends L.Map {
|
||||
#cameraZoomRatio: number = 1.0;
|
||||
|
||||
/* Coalition areas drawing */
|
||||
#coalitionAreas: CoalitionArea[] = [];
|
||||
#coalitionPolygons: CoalitionPolygon[] = [];
|
||||
|
||||
/* Unit context actions */
|
||||
#contextAction: null | ContextAction = null;
|
||||
@@ -102,7 +103,7 @@ export class Map extends L.Map {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ID - the ID of the HTML element which will contain the context menu
|
||||
* @param ID - the ID of the HTML element which will contain the map
|
||||
*/
|
||||
constructor(ID: string) {
|
||||
/* Init the leaflet map */
|
||||
@@ -111,7 +112,7 @@ export class Map extends L.Map {
|
||||
doubleClickZoom: false,
|
||||
zoomControl: false,
|
||||
boxZoom: false,
|
||||
//@ts-ignore Needed because the boxSelect option is non-standard
|
||||
//@ts-ignore Needed because the boxSelect option is non-standard and unsuppoerted
|
||||
boxSelect: true,
|
||||
zoomAnimation: true,
|
||||
maxBoundsViscosity: 1.0,
|
||||
@@ -154,10 +155,9 @@ export class Map extends L.Map {
|
||||
this.on("keydown", (e: any) => this.#onKeyDown(e));
|
||||
this.on("keyup", (e: any) => this.#onKeyUp(e));
|
||||
|
||||
this.on("move", (e: any) => {
|
||||
this.#onMapMove(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);
|
||||
|
||||
@@ -177,7 +177,6 @@ export class Map extends L.Map {
|
||||
document.addEventListener(
|
||||
"toggleCoalitionAreaDraw",
|
||||
(ev: CustomEventInit) => {
|
||||
//this.getMapContextMenu().hide();
|
||||
this.deselectAllCoalitionAreas();
|
||||
if (ev.detail?.type == "polygon") {
|
||||
if (this.getState() !== COALITIONAREA_DRAW_POLYGON)
|
||||
@@ -246,15 +245,11 @@ export class Map extends L.Map {
|
||||
});
|
||||
|
||||
document.addEventListener("toggleCameraLinkStatus", () => {
|
||||
// if (this.#slaveDCSCameraAvailable) { // Commented to experiment with usability
|
||||
this.setSlaveDCSCamera(!this.#slaveDCSCamera);
|
||||
// }
|
||||
});
|
||||
|
||||
document.addEventListener("slewCameraToPosition", () => {
|
||||
// if (this.#slaveDCSCameraAvailable) { // Commented to experiment with usability
|
||||
this.#broadcastPosition();
|
||||
// }
|
||||
});
|
||||
|
||||
/* Pan interval */
|
||||
@@ -368,26 +363,30 @@ export class Map extends L.Map {
|
||||
contextAction?: ContextAction | null;
|
||||
}
|
||||
) {
|
||||
this.#state = state;
|
||||
console.log(`Switching from state ${this.#state} to ${state}`);
|
||||
|
||||
/* Operations to perform if you are NOT in a state */
|
||||
if (this.#state !== COALITIONAREA_DRAW_POLYGON) {
|
||||
/* Operations to perform when leaving a state */
|
||||
if (this.#state === COALITIONAREA_DRAW_POLYGON) {
|
||||
this.getSelectedCoalitionArea()?.setEditing(false);
|
||||
}
|
||||
if (this.#state !== COALITIONAREA_EDIT) {
|
||||
this.#deselectSelectedCoalitionArea();
|
||||
}
|
||||
|
||||
/* Operations to perform if you ARE in a state */
|
||||
this.#state = state;
|
||||
|
||||
/* Operations to perform when entering a state */
|
||||
if (this.#state === IDLE) {
|
||||
getApp().getUnitsManager().deselectAllUnits();
|
||||
this.deselectAllCoalitionAreas();
|
||||
} else if (this.#state === SPAWN_UNIT) {
|
||||
this.#spawnRequestTable = options?.spawnRequestTable ?? null;
|
||||
console.log(`Spawn request table:`);
|
||||
console.log(this.#spawnRequestTable);
|
||||
} else if (this.#state === CONTEXT_ACTION) {
|
||||
this.#contextAction = options?.contextAction ?? null;
|
||||
console.log(`Context action:`);
|
||||
console.log(this.#contextAction);
|
||||
} else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
|
||||
this.#coalitionAreas.push(new CoalitionArea([]));
|
||||
this.#coalitionAreas[this.#coalitionAreas.length - 1].addTo(this);
|
||||
this.#coalitionPolygons.push(new CoalitionPolygon([]));
|
||||
this.#coalitionPolygons[this.#coalitionPolygons.length - 1].addTo(this);
|
||||
}
|
||||
|
||||
document.dispatchEvent(
|
||||
@@ -400,15 +399,15 @@ export class Map extends L.Map {
|
||||
}
|
||||
|
||||
deselectAllCoalitionAreas() {
|
||||
this.#coalitionAreas.forEach((coalitionArea: CoalitionArea) =>
|
||||
coalitionArea.setSelected(false)
|
||||
this.#coalitionPolygons.forEach((coalitionPolygon: CoalitionPolygon) =>
|
||||
coalitionPolygon.setSelected(false)
|
||||
);
|
||||
}
|
||||
|
||||
deleteCoalitionArea(coalitionArea: CoalitionArea) {
|
||||
if (this.#coalitionAreas.includes(coalitionArea))
|
||||
this.#coalitionAreas.splice(
|
||||
this.#coalitionAreas.indexOf(coalitionArea),
|
||||
deleteCoalitionArea(coalitionArea: CoalitionPolygon) {
|
||||
if (this.#coalitionPolygons.includes(coalitionArea))
|
||||
this.#coalitionPolygons.splice(
|
||||
this.#coalitionPolygons.indexOf(coalitionArea),
|
||||
1
|
||||
);
|
||||
if (this.hasLayer(coalitionArea)) this.removeLayer(coalitionArea);
|
||||
@@ -551,15 +550,15 @@ export class Map extends L.Map {
|
||||
}
|
||||
|
||||
getSelectedCoalitionArea() {
|
||||
return this.#coalitionAreas.find((area: CoalitionArea) => {
|
||||
return area.getSelected();
|
||||
return this.#coalitionPolygons.find((coalitionPolygon: CoalitionPolygon) => {
|
||||
return coalitionPolygon.getSelected();
|
||||
});
|
||||
}
|
||||
|
||||
bringCoalitionAreaToBack(coalitionArea: CoalitionArea) {
|
||||
bringCoalitionAreaToBack(coalitionArea: CoalitionPolygon) {
|
||||
coalitionArea.bringToBack();
|
||||
this.#coalitionAreas.splice(this.#coalitionAreas.indexOf(coalitionArea), 1);
|
||||
this.#coalitionAreas.unshift(coalitionArea);
|
||||
this.#coalitionPolygons.splice(this.#coalitionPolygons.indexOf(coalitionArea), 1);
|
||||
this.#coalitionPolygons.unshift(coalitionArea);
|
||||
}
|
||||
|
||||
setOption(key, value) {
|
||||
@@ -644,6 +643,12 @@ export class Map extends L.Map {
|
||||
this.#contextAction?.executeCallback(targetUnit, targetPosition);
|
||||
}
|
||||
|
||||
preventClicks() {
|
||||
console.log("Preventing clicks on map")
|
||||
window.clearTimeout(this.#shortPressTimer);
|
||||
window.clearTimeout(this.#longPressTimer);
|
||||
}
|
||||
|
||||
/* Event handlers */
|
||||
#onDragStart(e: any) {
|
||||
this.#isDragging = true;
|
||||
@@ -653,8 +658,7 @@ export class Map extends L.Map {
|
||||
this.#isDragging = false;
|
||||
}
|
||||
|
||||
#onSelectionStart(e: any) {
|
||||
}
|
||||
#onSelectionStart(e: any) {}
|
||||
|
||||
#onSelectionEnd(e: any) {
|
||||
getApp().getUnitsManager().selectFromBounds(e.selectionBounds);
|
||||
@@ -709,7 +713,6 @@ export class Map extends L.Map {
|
||||
|
||||
/* 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;
|
||||
@@ -733,11 +736,9 @@ export class Map extends L.Map {
|
||||
);
|
||||
}
|
||||
} else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
|
||||
if (this.getSelectedCoalitionArea()?.getEditing()) {
|
||||
this.getSelectedCoalitionArea()?.addTemporaryLatLng(location);
|
||||
} else {
|
||||
this.deselectAllCoalitionAreas();
|
||||
}
|
||||
this.getSelectedCoalitionArea()?.getEditing()
|
||||
? this.getSelectedCoalitionArea()?.addTemporaryLatLng(location)
|
||||
: this.deselectAllCoalitionAreas();
|
||||
} else if (this.#state === COALITIONAREA_EDIT) {
|
||||
this.deselectAllCoalitionAreas();
|
||||
} else if (this.#state === CONTEXT_ACTION) {
|
||||
@@ -750,7 +751,7 @@ export class Map extends L.Map {
|
||||
console.log(`Long press at ${e.latlng}`);
|
||||
|
||||
if (!this.#isDragging && !this.#isZooming) {
|
||||
if (this.getState() == IDLE) {
|
||||
if (this.#state == IDLE) {
|
||||
if (e.type === "touchstart")
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("mapForceBoxSelect", { detail: e })
|
||||
@@ -759,10 +760,10 @@ export class Map extends L.Map {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("mapForceBoxSelect", { detail: e.originalEvent })
|
||||
);
|
||||
} 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);
|
||||
} else if (this.#state == COALITIONAREA_EDIT) {
|
||||
for (let idx = 0; idx < this.#coalitionPolygons.length; idx++) {
|
||||
if (polyContains(e.latlng, this.#coalitionPolygons[idx])) {
|
||||
this.#coalitionPolygons[idx].setSelected(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -776,11 +777,6 @@ export class Map extends L.Map {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#onMapMove(e: any) {
|
||||
@@ -864,10 +860,6 @@ export class Map extends L.Map {
|
||||
return minimapBoundaries;
|
||||
}
|
||||
|
||||
#deselectSelectedCoalitionArea() {
|
||||
this.getSelectedCoalitionArea()?.setSelected(false);
|
||||
}
|
||||
|
||||
#setSlaveDCSCameraAvailable(newSlaveDCSCameraAvailable: boolean) {
|
||||
this.#slaveDCSCameraAvailable = newSlaveDCSCameraAvailable;
|
||||
let linkButton = document.getElementById("camera-link-control");
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// This is a horrible hack. But it is needed at the moment to ovveride a default behaviour of Leaflet. TODO please fix me the proper way.
|
||||
// @ts-nocheck <-- This is a horrible hack. But it is needed at the moment to ovveride a default behaviour of Leaflet. TODO please fix me the proper way.
|
||||
|
||||
import { Circle, Point, Polyline } from "leaflet";
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
DateAndTime,
|
||||
MissionData,
|
||||
} from "../interfaces";
|
||||
import { Coalition } from "../types/types";
|
||||
|
||||
/** The MissionManager */
|
||||
export class MissionManager {
|
||||
@@ -253,10 +254,10 @@ export class MissionManager {
|
||||
|
||||
getCommandedCoalition() {
|
||||
if (this.getCommandModeOptions().commandMode === BLUE_COMMANDER)
|
||||
return "blue";
|
||||
return "blue" as Coalition;
|
||||
else if (this.getCommandModeOptions().commandMode === RED_COMMANDER)
|
||||
return "red";
|
||||
else return "all";
|
||||
return "red" as Coalition;
|
||||
else return "all" as Coalition;
|
||||
}
|
||||
|
||||
refreshSpawnPoints() {
|
||||
@@ -395,14 +396,7 @@ export class MissionManager {
|
||||
}
|
||||
|
||||
#onAirbaseClick(e: any) {
|
||||
getApp()
|
||||
.getMap()
|
||||
.showAirbaseContextMenu(
|
||||
e.sourceTarget,
|
||||
e.originalEvent.x,
|
||||
e.originalEvent.y,
|
||||
e.latlng
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#loadAirbaseChartData(callsign: string) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { LatLng, Point, Polygon } from "leaflet";
|
||||
import { LatLng, Polygon } from "leaflet";
|
||||
import * as turf from "@turf/turf";
|
||||
import { UnitDatabase } from "../unit/databases/unitdatabase";
|
||||
import {
|
||||
AircraftDatabase,
|
||||
aircraftDatabase,
|
||||
} from "../unit/databases/aircraftdatabase";
|
||||
import { helicopterDatabase } from "../unit/databases/helicopterdatabase";
|
||||
import { groundUnitDatabase } from "../unit/databases/groundunitdatabase";
|
||||
//import { Buffer } from "buffer";
|
||||
import {
|
||||
GROUND_UNIT_AIR_DEFENCE_REGEX,
|
||||
ROEs,
|
||||
emissionsCountermeasures,
|
||||
reactionsToThreat,
|
||||
@@ -290,12 +287,6 @@ export function mercatorToLatLng(x: number, y: number) {
|
||||
return { lng: lng, lat: lat };
|
||||
}
|
||||
|
||||
export function createDivWithClass(className: string) {
|
||||
var el = document.createElement("div");
|
||||
el.classList.add(className);
|
||||
return el;
|
||||
}
|
||||
|
||||
export function knotsToMs(knots: number) {
|
||||
return knots / 1.94384;
|
||||
}
|
||||
@@ -325,10 +316,17 @@ export function nmToFt(nm: number) {
|
||||
}
|
||||
|
||||
export function polyContains(latlng: LatLng, polygon: Polygon) {
|
||||
var poly = polygon.toGeoJSON();
|
||||
const poly = polygon.toGeoJSON();
|
||||
return turf.inside(turf.point([latlng.lng, latlng.lat]), poly);
|
||||
}
|
||||
|
||||
export function polyCenter(polygon: Polygon) {
|
||||
const poly = polygon.toGeoJSON();
|
||||
const center = turf.center(poly);
|
||||
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();
|
||||
@@ -450,10 +448,6 @@ export function getUnitCategoryByBlueprint(blueprint: UnitBlueprint) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
export function base64ToBytes(base64: string) {
|
||||
//return Buffer.from(base64, 'base64').buffer;
|
||||
}
|
||||
|
||||
export function enumToState(state: number) {
|
||||
if (state < states.length) return states[state];
|
||||
else return states[0];
|
||||
|
||||
@@ -175,7 +175,7 @@ export class ServerManager {
|
||||
}
|
||||
|
||||
setAddress(address: string) {
|
||||
this.#REST_ADDRESS = `${address.replace('vite', '')}olympus`;
|
||||
this.#REST_ADDRESS = `${address.replace('vite/', '')}olympus`;
|
||||
console.log(`Setting REST address to ${this.#REST_ADDRESS}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,6 @@ export type MGRS = {
|
||||
zoneNumber: string;
|
||||
};
|
||||
|
||||
export type Coalition = "blue" | "neutral" | "red";
|
||||
export type Coalition = "blue" | "neutral" | "red" | "all";
|
||||
|
||||
export type Context = string;
|
||||
|
||||
@@ -1,19 +1,67 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Menu } from "./components/menu";
|
||||
import { FaQuestionCircle } from "react-icons/fa";
|
||||
import { FaQuestionCircle, FaRegCircle } from "react-icons/fa";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { COALITIONAREA_DRAW_POLYGON, COALITIONAREA_EDIT, IDLE } from "../../constants/constants";
|
||||
import {
|
||||
COALITIONAREA_DRAW_POLYGON,
|
||||
COALITIONAREA_EDIT,
|
||||
IDLE,
|
||||
} from "../../constants/constants";
|
||||
import { OlStateButton } from "../components/olstatebutton";
|
||||
import { faDrawPolygon } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { CoalitionPolygon } from "../../map/coalitionarea/coalitionpolygon";
|
||||
import { OlCoalitionToggle } from "../components/olcoalitiontoggle";
|
||||
import { OlDropdown, OlDropdownItem } from "../components/oldropdown";
|
||||
import { OlCheckbox } from "../components/olcheckbox";
|
||||
import { Coalition } from "../../types/types";
|
||||
import { OlRangeSlider } from "../components/olrangeslider";
|
||||
|
||||
export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
const [drawingPolygon, setDrawingPolygon] = useState(false);
|
||||
const [drawingCircle, setDrawingCircle] = useState(false);
|
||||
const [activeCoalitionArea, setActiveCoalitionArea] = useState(
|
||||
null as null | CoalitionPolygon
|
||||
);
|
||||
const [areaCoalition, setAreaCoalition] = useState("blue" as Coalition);
|
||||
const [IADSDensity, setIADSDensity] = useState(50);
|
||||
const [IADSDistribution, setIADSDistribution] = useState(50);
|
||||
const [forceCoalitionAppropriateUnits, setForceCoalitionApproriateUnits] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.open && !drawingPolygon) {
|
||||
if (
|
||||
drawingPolygon &&
|
||||
getApp().getMap().getState() !== COALITIONAREA_DRAW_POLYGON
|
||||
)
|
||||
setDrawingPolygon(false);
|
||||
|
||||
if (props.open && !drawingPolygon)
|
||||
getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
|
||||
if (
|
||||
activeCoalitionArea &&
|
||||
activeCoalitionArea?.getCoalition() !== areaCoalition
|
||||
)
|
||||
setAreaCoalition(activeCoalitionArea?.getCoalition());
|
||||
});
|
||||
|
||||
document.addEventListener("mapStateChanged", (event: any) => {
|
||||
if (
|
||||
drawingPolygon &&
|
||||
getApp().getMap().getState() !== COALITIONAREA_DRAW_POLYGON
|
||||
)
|
||||
setDrawingPolygon(false);
|
||||
|
||||
if (
|
||||
[COALITIONAREA_DRAW_POLYGON, COALITIONAREA_EDIT].includes(
|
||||
getApp().getMap().getState()
|
||||
)
|
||||
) {
|
||||
setActiveCoalitionArea(
|
||||
getApp().getMap().getSelectedCoalitionArea() ?? null
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<Menu
|
||||
@@ -26,7 +74,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
The draw tool allows you to quickly draw areas on the map and use these
|
||||
areas to spawn units and activate triggers.
|
||||
</div>
|
||||
<div className="mx-6 my-2 flex rounded-lg bg-olympus-400 p-4 text-sm">
|
||||
<div className="mx-6 flex rounded-lg bg-olympus-400 p-4 text-sm">
|
||||
<div>
|
||||
<FaQuestionCircle className="my-4 ml-2 mr-6 text-gray-400" />
|
||||
</div>
|
||||
@@ -40,22 +88,168 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6 text-sm text-gray-400">
|
||||
<OlStateButton
|
||||
className="!w-full"
|
||||
icon={faDrawPolygon}
|
||||
tooltip={"Add a new polygon"}
|
||||
checked={drawingPolygon}
|
||||
onClick={() => {
|
||||
if (drawingPolygon)
|
||||
getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
else
|
||||
getApp().getMap().setState(COALITIONAREA_DRAW_POLYGON);
|
||||
setDrawingPolygon(!drawingPolygon);
|
||||
}}
|
||||
>
|
||||
<div className="text-sm">Add polygon</div>
|
||||
</OlStateButton>
|
||||
<>
|
||||
{activeCoalitionArea === null && (
|
||||
<div className="flex flex-col gap-2 p-6 text-sm text-gray-400">
|
||||
<OlStateButton
|
||||
className="!w-full"
|
||||
icon={faDrawPolygon}
|
||||
tooltip={"Add a new polygon"}
|
||||
checked={drawingPolygon}
|
||||
onClick={() => {
|
||||
if (drawingPolygon)
|
||||
getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
else getApp().getMap().setState(COALITIONAREA_DRAW_POLYGON);
|
||||
setDrawingPolygon(!drawingPolygon);
|
||||
}}
|
||||
>
|
||||
<div className="text-sm">Add polygon</div>
|
||||
</OlStateButton>
|
||||
<OlStateButton
|
||||
className="!w-full"
|
||||
icon={faCircle}
|
||||
tooltip={"Add a new circle"}
|
||||
checked={drawingCircle}
|
||||
onClick={() => {}}
|
||||
>
|
||||
<div className="text-sm">Add circle (WIP)</div>
|
||||
</OlStateButton>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
<div>
|
||||
{activeCoalitionArea !== null && (
|
||||
<div className={`flex flex-col gap-4 py-4`}>
|
||||
<div
|
||||
className={`
|
||||
flex flex-col content-center justify-start gap-2 px-6
|
||||
text-gray-200
|
||||
`}
|
||||
>
|
||||
<div className="my-auto text-md">Area label </div>
|
||||
<input
|
||||
type="text"
|
||||
className={`
|
||||
block max-w-80 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
|
||||
dark:focus:ring-blue-500
|
||||
focus:border-blue-500 focus:ring-blue-500
|
||||
`}
|
||||
defaultValue={activeCoalitionArea.getLabelText()}
|
||||
onInput={(ev) =>
|
||||
activeCoalitionArea.setLabelText(ev.currentTarget.value)
|
||||
}
|
||||
></input>
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
flex content-center justify-start gap-4 px-6 text-gray-200
|
||||
`}
|
||||
>
|
||||
<div className="my-auto text-md">Coalition: </div>
|
||||
<OlCoalitionToggle
|
||||
coalition={areaCoalition}
|
||||
onClick={() => {
|
||||
let newCoalition = "";
|
||||
if (areaCoalition === "blue") newCoalition = "neutral";
|
||||
else if (areaCoalition === "neutral") newCoalition = "red";
|
||||
else if (areaCoalition === "red") newCoalition = "blue";
|
||||
setAreaCoalition(newCoalition as Coalition);
|
||||
activeCoalitionArea.setCoalition(newCoalition as Coalition);
|
||||
}}
|
||||
></OlCoalitionToggle>
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
flex flex-col gap-3 border-l-4 border-l-olympus-100
|
||||
bg-olympus-600 p-5
|
||||
`}
|
||||
>
|
||||
<div className="border-b-2 border-b-olympus-100 pb-4 text-gray-300">
|
||||
Automatic IADS generation
|
||||
</div>
|
||||
<OlDropdown className="" label="Units types">
|
||||
{getApp()
|
||||
.getGroundUnitDatabase()
|
||||
.getTypes()
|
||||
.map((era) => {
|
||||
return (
|
||||
<OlDropdownItem className={`flex gap-4`}>
|
||||
<OlCheckbox checked={true} onChange={() => {}} />
|
||||
{era}
|
||||
</OlDropdownItem>
|
||||
);
|
||||
})}
|
||||
</OlDropdown>
|
||||
<OlDropdown className="" label="Units eras">
|
||||
{getApp()
|
||||
.getGroundUnitDatabase()
|
||||
.getEras()
|
||||
.map((era) => {
|
||||
return (
|
||||
<OlDropdownItem className={`flex gap-4`}>
|
||||
<OlCheckbox checked={true} onChange={() => {}} />
|
||||
{era}
|
||||
</OlDropdownItem>
|
||||
);
|
||||
})}
|
||||
</OlDropdown>
|
||||
<OlDropdown className="" label="Units ranges">
|
||||
{["Short range", "Medium range", "Long range"].map((era) => {
|
||||
return (
|
||||
<OlDropdownItem className={`flex gap-4`}>
|
||||
<OlCheckbox checked={true} onChange={() => {}} />
|
||||
{era}
|
||||
</OlDropdownItem>
|
||||
);
|
||||
})}
|
||||
</OlDropdown>
|
||||
<div>
|
||||
<div className="flex justify-between">
|
||||
<div className="text-gray-100">IADS Density</div>
|
||||
<div
|
||||
className={`
|
||||
font-bold
|
||||
dark:text-blue-500
|
||||
`}
|
||||
>
|
||||
50%
|
||||
</div>
|
||||
</div>
|
||||
<OlRangeSlider value={50} onChange={() => {}}></OlRangeSlider>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between">
|
||||
<div className="text-gray-100">IADS Distribution</div>
|
||||
<div
|
||||
className={`
|
||||
font-bold
|
||||
dark:text-blue-500
|
||||
`}
|
||||
>
|
||||
50%
|
||||
</div>
|
||||
</div>
|
||||
<OlRangeSlider value={IADSDistribution} onChange={(ev) => {setIADSDistribution(Number(ev.target.value))}}></OlRangeSlider>
|
||||
</div>
|
||||
<div className="flex content-center gap-4 text-gray-200">
|
||||
<OlCheckbox checked={forceCoalitionAppropriateUnits} onChange={() => {
|
||||
setForceCoalitionApproriateUnits(!forceCoalitionAppropriateUnits);
|
||||
}} />
|
||||
Force coalition appropriate units
|
||||
</div>
|
||||
<button type="button" className={`
|
||||
mb-2 me-2 rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium
|
||||
text-white
|
||||
dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800
|
||||
focus:outline-none focus:ring-4 focus:ring-blue-300
|
||||
hover:bg-blue-800
|
||||
`}>Generate IADS</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Menu } from "./components/menu";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||
@@ -75,12 +75,13 @@ export function SpawnMenu(props: {
|
||||
filteredAirDefense = filterUnits(filteredAirDefense, filterString);
|
||||
filteredGroundUnits = filterUnits(filteredGroundUnits, filterString);
|
||||
|
||||
if (!props.open) {
|
||||
if (getApp()?.getMap()?.getState() === SPAWN_UNIT)
|
||||
getApp().getMap().setState(IDLE);
|
||||
if (blueprint !== null)
|
||||
setBlueprint(null);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (!props.open) {
|
||||
if (getApp()?.getMap()?.getState() === SPAWN_UNIT)
|
||||
getApp().getMap().setState(IDLE);
|
||||
if (blueprint !== null) setBlueprint(null);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Menu
|
||||
@@ -98,9 +99,11 @@ export function SpawnMenu(props: {
|
||||
<div className="p-5">
|
||||
<OlSearchBar onChange={(ev) => setFilterString(ev.target.value)} />
|
||||
<OlAccordion title={`Aircraft`}>
|
||||
<div className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}
|
||||
>
|
||||
{Object.keys(filteredAircraft).map((key) => {
|
||||
const blueprint =
|
||||
getApp().getAircraftDatabase().blueprints[key];
|
||||
@@ -116,9 +119,11 @@ export function SpawnMenu(props: {
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion title={`Helicopters`}>
|
||||
<div className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}
|
||||
>
|
||||
{Object.keys(filteredHelicopters).map((key) => {
|
||||
const blueprint =
|
||||
getApp().getHelicopterDatabase().blueprints[key];
|
||||
@@ -134,9 +139,11 @@ export function SpawnMenu(props: {
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion title={`SAM & AAA`}>
|
||||
<div className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}
|
||||
>
|
||||
{Object.keys(filteredAirDefense).map((key) => {
|
||||
const blueprint =
|
||||
getApp().getGroundUnitDatabase().blueprints[key];
|
||||
@@ -152,9 +159,11 @@ export function SpawnMenu(props: {
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion title={`Ground Units`}>
|
||||
<div className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}
|
||||
>
|
||||
{Object.keys(filteredGroundUnits).map((key) => {
|
||||
const blueprint =
|
||||
getApp().getGroundUnitDatabase().blueprints[key];
|
||||
@@ -170,9 +179,11 @@ export function SpawnMenu(props: {
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion title={`Ships and submarines`}>
|
||||
<div className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
|
||||
`}
|
||||
>
|
||||
{Object.keys(filteredNavyUnits).map((key) => {
|
||||
const blueprint =
|
||||
getApp().getNavyUnitDatabase().blueprints[key];
|
||||
|
||||
@@ -118,7 +118,7 @@ export abstract class UnitDatabase {
|
||||
return types;
|
||||
}
|
||||
|
||||
/* Returns a list of all possible periods in a database */
|
||||
/* Returns a list of all possible eras in a database */
|
||||
getEras() {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var eras: string[] = [];
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
randomPointInPoly,
|
||||
randomUnitBlueprint,
|
||||
} from "../other/utils";
|
||||
import { CoalitionArea } from "../map/coalitionarea/coalitionarea";
|
||||
import { CoalitionPolygon } from "../map/coalitionarea/coalitionpolygon";
|
||||
import { groundUnitDatabase } from "./databases/groundunitdatabase";
|
||||
import {
|
||||
DELETE_CYCLE_TIME,
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
DataIndexes,
|
||||
GAME_MASTER,
|
||||
IADSDensities,
|
||||
IDLE
|
||||
IDLE,
|
||||
} from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { citiesDatabase } from "./databases/citiesdatabase";
|
||||
@@ -1642,7 +1642,7 @@ export class UnitsManager {
|
||||
* @param distribution Value between 0 and 100, controls how "scattered" the units will be
|
||||
*/
|
||||
createIADS(
|
||||
coalitionArea: CoalitionArea,
|
||||
coalitionArea: CoalitionPolygon,
|
||||
types: { [key: string]: boolean },
|
||||
eras: { [key: string]: boolean },
|
||||
ranges: { [key: string]: boolean },
|
||||
|
||||
Reference in New Issue
Block a user