Started adding controls panel for shortcuts, more work on better polygon creation, added circles creation

This commit is contained in:
Pax1601
2024-08-01 09:02:21 +02:00
parent 1e72f15876
commit 86e0e6b3a3
14 changed files with 675 additions and 150 deletions

View File

@@ -0,0 +1,5 @@
const CoalitionArea = Base => class extends Base {
}
export CoalitionArea;

View File

@@ -0,0 +1,162 @@
import {
LatLngExpression,
Map,
Circle,
DivIcon,
Marker,
CircleOptions,
LatLng,
} from "leaflet";
import { getApp } from "../../olympusapp";
import { CoalitionAreaHandle } from "./coalitionareahandle";
import { BLUE_COMMANDER, RED_COMMANDER } from "../../constants/constants";
import { Coalition } from "../../types/types";
import * as turf from "@turf/turf";
let totalAreas = 0;
export class CoalitionCircle extends Circle {
#coalition: Coalition = "blue";
#selected: boolean = true;
#editing: boolean = true;
#radiusHandle: CoalitionAreaHandle;
#labelText: string;
#label: Marker;
constructor(latlng: LatLngExpression, options: CircleOptions) {
if (options === undefined) options = { radius: 0 };
totalAreas++;
options.bubblingMouseEvents = false;
options.interactive = false;
//@ts-ignore draggable option added by leaflet-path-drag
options.draggable = true;
super(latlng, options);
this.#setColors();
this.#labelText = `Circle ${totalAreas}`;
if (
[BLUE_COMMANDER, RED_COMMANDER].includes(
getApp().getMissionManager().getCommandModeOptions().commandMode
)
)
this.setCoalition(getApp().getMissionManager().getCommandedCoalition());
this.on("drag", () => {
this.#setRadiusHandle();
this.#drawLabel();
});
}
setCoalition(coalition: Coalition) {
this.#coalition = coalition;
this.#setColors();
}
getCoalition() {
return this.#coalition;
}
setSelected(selected: boolean) {
this.#selected = selected;
this.#setColors();
this.#setRadiusHandle();
this.#drawLabel();
this.setOpacity(selected ? 1 : 0.5);
//@ts-ignore draggable option added by leaflet-path-drag
selected ? this.dragging.enable() : this.dragging.disable();
}
getSelected() {
return this.#selected;
}
setEditing(editing: boolean) {
this.#editing = editing;
this.#setRadiusHandle();
}
getEditing() {
return this.#editing;
}
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);
this.#radiusHandle.removeFrom(getApp().getMap());
return this;
}
setLatLng(latlng: LatLngExpression): this {
super.setLatLng(latlng);
this.#setRadiusHandle();
this.#drawLabel();
return this;
}
#setColors() {
let coalitionColor = "#FFFFFF";
if (this.getCoalition() === "blue") coalitionColor = "#247be2";
else if (this.getCoalition() === "red") coalitionColor = "#ff5858";
this.setStyle({
color: this.getSelected() ? "white" : coalitionColor,
fillColor: coalitionColor,
});
}
#setRadiusHandle() {
if (this.#radiusHandle) this.#radiusHandle.removeFrom(getApp().getMap());
if (this.#selected) {
const dest = turf.destination(
turf.point([this.getLatLng().lng, this.getLatLng().lat]),
this.getRadius() / 1000,
0
);
this.#radiusHandle = new CoalitionAreaHandle(
new LatLng(dest.geometry.coordinates[1], dest.geometry.coordinates[0])
);
this.#radiusHandle.addTo(getApp().getMap());
this.#radiusHandle.on("drag", (e: any) => {
this.setRadius(this.getLatLng().distanceTo(e.latlng));
});
}
}
#drawLabel() {
if (this.#label) {
this.#label.removeFrom(this._map);
}
this.#label = new Marker(this.getLatLng(), {
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}`}`
);
}
}

View File

@@ -6,7 +6,7 @@ import {
Polygon,
PolylineOptions,
DivIcon,
Marker
Marker,
} from "leaflet";
import { getApp } from "../../olympusapp";
import { CoalitionAreaHandle } from "./coalitionareahandle";
@@ -37,11 +37,13 @@ export class CoalitionPolygon extends Polygon {
options.bubblingMouseEvents = false;
options.interactive = false;
//@ts-ignore draggable option added by leaflet-path-drag
options.draggable = true;
super(latlngs, options);
this.#setColors();
this.#labelText = `Polygon ${totalAreas}`
this.#labelText = `Polygon ${totalAreas}`;
if (
[BLUE_COMMANDER, RED_COMMANDER].includes(
@@ -49,6 +51,12 @@ export class CoalitionPolygon extends Polygon {
)
)
this.setCoalition(getApp().getMissionManager().getCommandedCoalition());
this.on("drag", () => {
this.#setHandles();
this.#setMiddleHandles();
this.#drawLabel();
});
}
setCoalition(coalition: Coalition) {
@@ -73,6 +81,9 @@ export class CoalitionPolygon extends Polygon {
this.setLatLngs(latlngs);
this.setEditing(false);
}
//@ts-ignore draggable option added by leaflet-path-drag
selected ? this.dragging.enable() : this.dragging.disable();
}
getSelected() {
@@ -103,7 +114,7 @@ export class CoalitionPolygon extends Polygon {
setOpacity(opacity: number) {
this.setStyle({ opacity: opacity, fillOpacity: opacity * 0.25 });
}
getLabelText() {
return this.#labelText;
}
@@ -123,15 +134,19 @@ export class CoalitionPolygon extends Polygon {
return this;
}
setLatLngs(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]){
setLatLngs(
latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]
) {
super.setLatLngs(latlngs);
this.#drawLabel();
return this;
}
#setColors() {
const coalitionColor =
this.getCoalition() === "blue" ? "#247be2" : "#ff5858";
let coalitionColor = "#FFFFFF";
if (this.getCoalition() === "blue") coalitionColor = "#247be2";
else if (this.getCoalition() === "red") coalitionColor = "#ff5858";
this.setStyle({
color: this.getSelected() ? "white" : coalitionColor,
fillColor: coalitionColor,
@@ -196,18 +211,25 @@ export class CoalitionPolygon extends Polygon {
}
}
#drawLabel() {
if (this.#label) {
this.#label.removeFrom(this._map);
#drawLabel() {
if (this.#label) {
this.#label.removeFrom(this._map);
}
if ((this.getLatLngs()[0] as LatLng[]).length > 2) {
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}`}`
);
}
}
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}`}`);
}
}

View File

@@ -1,22 +0,0 @@
import { DivIcon, LatLng } from "leaflet";
import { CustomMarker } from "../markers/custommarker";
export class DrawingCursor extends CustomMarker {
constructor() {
super(new LatLng(0, 0), { interactive: false });
this.setZIndexOffset(9999);
}
createIcon() {
this.setIcon(
new DivIcon({
iconSize: [24, 24],
iconAnchor: [0, 24],
className: "leaflet-draw-marker",
})
);
var el = document.createElement("div");
el.classList.add("ol-draw-icon");
this.getElement()?.appendChild(el);
}
}

View File

@@ -3,7 +3,13 @@ import { getApp } from "../olympusapp";
import { BoxSelect } from "./boxselect";
import { Airbase } from "../mission/airbase";
import { Unit } from "../unit/unit";
import { deg2rad, getGroundElevation, polyContains } from "../other/utils";
import {
areaContains,
circleContains,
deg2rad,
getGroundElevation,
polyContains,
} from "../other/utils";
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
import { ClickableMiniMap } from "./clickableminimap";
import {
@@ -18,6 +24,7 @@ import {
MAP_OPTIONS_DEFAULTS,
MAP_HIDDEN_TYPES_DEFAULTS,
COALITIONAREA_EDIT,
COALITIONAREA_DRAW_CIRCLE,
} from "../constants/constants";
import { CoalitionPolygon } from "./coalitionarea/coalitionpolygon";
import { MapHiddenTypes, MapOptions } from "../types/types";
@@ -29,6 +36,10 @@ import "./markers/stylesheets/airbase.css";
import "./markers/stylesheets/bullseye.css";
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";
/* Register the handler for the box selection */
L.Map.addInitHook("addHandler", "boxSelect", BoxSelect);
@@ -92,7 +103,7 @@ export class Map extends L.Map {
#cameraZoomRatio: number = 1.0;
/* Coalition areas drawing */
#coalitionPolygons: CoalitionPolygon[] = [];
#coalitionAreas: (CoalitionPolygon | CoalitionCircle)[] = [];
/* Unit context actions */
#contextAction: null | ContextAction = null;
@@ -132,7 +143,7 @@ export class Map extends L.Map {
this.#miniMapPolyline.addTo(this.#miniMapLayerGroup);
/* Init the state machine */
this.#state = IDLE;
this.setState(IDLE);
/* Register event handles */
this.on("zoomstart", (e: any) => this.#onZoomStart(e));
@@ -174,18 +185,6 @@ export class Map extends L.Map {
);
});
document.addEventListener(
"toggleCoalitionAreaDraw",
(ev: CustomEventInit) => {
this.deselectAllCoalitionAreas();
if (ev.detail?.type == "polygon") {
if (this.getState() !== COALITIONAREA_DRAW_POLYGON)
this.setState(COALITIONAREA_DRAW_POLYGON);
else this.setState(IDLE);
}
}
);
//document.addEventListener("unitUpdated", (ev: CustomEvent) => {
// if (this.#centerUnit != null && ev.detail == this.#centerUnit)
// this.#panToUnit(this.#centerUnit);
@@ -366,27 +365,38 @@ export class Map extends L.Map {
console.log(`Switching from state ${this.#state} to ${state}`);
/* Operations to perform when leaving a state */
if (this.#state === COALITIONAREA_DRAW_POLYGON) {
if (
this.#state === COALITIONAREA_DRAW_POLYGON ||
this.#state === COALITIONAREA_DRAW_CIRCLE
)
this.getSelectedCoalitionArea()?.setEditing(false);
}
this.#state = state;
/* Operations to perform when entering a state */
if (this.#state === IDLE) {
getApp().getUnitsManager().deselectAllUnits();
getApp().getUnitsManager()?.deselectAllUnits();
this.deselectAllCoalitionAreas();
} else if (this.#state === SPAWN_UNIT) {
this.deselectAllCoalitionAreas();
this.#spawnRequestTable = options?.spawnRequestTable ?? null;
console.log(`Spawn request table:`);
console.log(this.#spawnRequestTable);
} else if (this.#state === CONTEXT_ACTION) {
this.deselectAllCoalitionAreas();
this.#contextAction = options?.contextAction ?? null;
console.log(`Context action:`);
console.log(this.#contextAction);
} else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
this.#coalitionPolygons.push(new CoalitionPolygon([]));
this.#coalitionPolygons[this.#coalitionPolygons.length - 1].addTo(this);
getApp().getUnitsManager().deselectAllUnits();
this.#coalitionAreas.push(new CoalitionPolygon([]));
this.#coalitionAreas[this.#coalitionAreas.length - 1].addTo(this);
} else if (this.#state === COALITIONAREA_DRAW_CIRCLE) {
getApp().getUnitsManager().deselectAllUnits();
this.#coalitionAreas.push(
new CoalitionCircle(new L.LatLng(0, 0), { radius: 1000 })
);
this.#coalitionAreas[this.#coalitionAreas.length - 1].addTo(this);
}
document.dispatchEvent(
@@ -398,18 +408,122 @@ export class Map extends L.Map {
return this.#state;
}
getCurrentControls() {
if (this.#state === IDLE) {
return [
{
actions: ["Tap"],
text: "Select unit",
},
{
actions: ["Shift", "Drag"],
text: "Box selection",
},
{
actions: ["Drag"],
text: "Move map location",
},
{
actions: ["Long tap", "Drag"],
text: "Box selection",
},
];
} else if (this.#state === SPAWN_UNIT) {
return [
{
actions: ["Tap"],
text: "Spawn unit",
},
{
actions: ["Double tap"],
text: "Exit spawn mode",
},
{
actions: ["Drag"],
text: "Move map location",
},
];
} else if (this.#state === CONTEXT_ACTION) {
return [
{
actions: ["Tap"],
text: this.#contextAction?.getLabel() ?? "",
},
{
actions: ["Double tap"],
text: "Exit action mode",
},
{
actions: ["Drag"],
text: "Move map location",
},
];
} else if (this.#state === COALITIONAREA_EDIT) {
return [
{
actions: ["Tap"],
text: "Select shape",
},
{
actions: ["Double tap"],
text: "Exit drawing mode",
},
{
actions: ["Drag"],
text: "Move map location",
},
];
} else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
return [
{
actions: ["Tap"],
text: "Add vertex to polygon",
},
{
actions: ["Double tap"],
text: "Finalize polygon",
},
{
actions: ["Drag"],
text: "Move map location",
},
];
} else if (this.#state === COALITIONAREA_DRAW_CIRCLE) {
return [
{
actions: ["Tap"],
text: "Add circle",
},
{
actions: ["Drag"],
text: "Move map location",
},
];
} else {
return [];
}
}
deselectAllCoalitionAreas() {
this.#coalitionPolygons.forEach((coalitionPolygon: CoalitionPolygon) =>
coalitionPolygon.setSelected(false)
document.dispatchEvent(
new CustomEvent("coalitionAreaSelected", {
detail: null,
})
);
this.#coalitionAreas.forEach(
(coalitionArea: CoalitionPolygon | CoalitionCircle) =>
coalitionArea.setSelected(false)
);
}
deleteCoalitionArea(coalitionArea: CoalitionPolygon) {
if (this.#coalitionPolygons.includes(coalitionArea))
this.#coalitionPolygons.splice(
this.#coalitionPolygons.indexOf(coalitionArea),
deleteCoalitionArea(coalitionArea: CoalitionPolygon | CoalitionCircle) {
if (this.#coalitionAreas.includes(coalitionArea))
this.#coalitionAreas.splice(
this.#coalitionAreas.indexOf(coalitionArea),
1
);
if (this.hasLayer(coalitionArea)) this.removeLayer(coalitionArea);
}
@@ -550,15 +664,13 @@ export class Map extends L.Map {
}
getSelectedCoalitionArea() {
return this.#coalitionPolygons.find((coalitionPolygon: CoalitionPolygon) => {
return coalitionPolygon.getSelected();
});
}
const coalitionArea = this.#coalitionAreas.find(
(coalitionArea: CoalitionPolygon | CoalitionCircle) => {
return coalitionArea.getSelected();
}
);
bringCoalitionAreaToBack(coalitionArea: CoalitionPolygon) {
coalitionArea.bringToBack();
this.#coalitionPolygons.splice(this.#coalitionPolygons.indexOf(coalitionArea), 1);
this.#coalitionPolygons.unshift(coalitionArea);
return coalitionArea ?? null;
}
setOption(key, value) {
@@ -644,7 +756,7 @@ export class Map extends L.Map {
}
preventClicks() {
console.log("Preventing clicks on map")
console.log("Preventing clicks on map");
window.clearTimeout(this.#shortPressTimer);
window.clearTimeout(this.#longPressTimer);
}
@@ -699,7 +811,10 @@ export class Map extends L.Map {
window.clearTimeout(this.#shortPressTimer);
window.clearTimeout(this.#longPressTimer);
if (this.#state === COALITIONAREA_DRAW_POLYGON) {
if (
this.#state === COALITIONAREA_DRAW_POLYGON ||
this.#state === COALITIONAREA_DRAW_CIRCLE
) {
this.setState(COALITIONAREA_EDIT);
} else {
this.setState(IDLE);
@@ -736,11 +851,33 @@ export class Map extends L.Map {
);
}
} else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
this.getSelectedCoalitionArea()?.getEditing()
? this.getSelectedCoalitionArea()?.addTemporaryLatLng(location)
: this.deselectAllCoalitionAreas();
} else if (this.#state === COALITIONAREA_EDIT) {
const selectedArea = this.getSelectedCoalitionArea();
if (selectedArea && selectedArea instanceof CoalitionPolygon) {
selectedArea.addTemporaryLatLng(location);
}
} else if (this.#state === COALITIONAREA_DRAW_CIRCLE) {
const selectedArea = this.getSelectedCoalitionArea();
if (selectedArea && selectedArea instanceof CoalitionCircle) {
if (
selectedArea.getLatLng().lat == 0 &&
selectedArea.getLatLng().lng == 0
)
selectedArea.setLatLng(location);
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])) {
this.#coalitionAreas[idx].setSelected(true);
document.dispatchEvent(
new CustomEvent("coalitionAreaSelected", {
detail: this.#coalitionAreas[idx],
})
);
break;
}
}
} else if (this.#state === CONTEXT_ACTION) {
this.executeContextAction(null, e.latlng);
} else {
@@ -750,6 +887,8 @@ export class Map extends L.Map {
#onLongPress(e: any) {
console.log(`Long press at ${e.latlng}`);
this.deselectAllCoalitionAreas();
if (!this.#isDragging && !this.#isZooming) {
if (this.#state == IDLE) {
if (e.type === "touchstart")
@@ -760,13 +899,6 @@ export class Map extends L.Map {
document.dispatchEvent(
new CustomEvent("mapForceBoxSelect", { detail: e.originalEvent })
);
} 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;
}
}
}
}
}