mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feature(drawings): Navpoints separated from Drawings
Known issue: navpoints settings are not saved in session, to be fixed.
This commit is contained in:
parent
4062e69661
commit
1262c85802
@ -648,17 +648,17 @@ export class AWACSReferenceChangedEvent {
|
||||
}
|
||||
|
||||
export class DrawingsInitEvent {
|
||||
static on(callback: (drawingsData: any /*TODO*/) => void, singleShot = false) {
|
||||
static on(callback: (drawingsData: any, navpointData: any /*TODO*/) => void, singleShot = false) {
|
||||
document.addEventListener(
|
||||
this.name,
|
||||
(ev: CustomEventInit) => {
|
||||
callback(ev.detail);
|
||||
callback(ev.detail.drawingsData, ev.detail.navpointData);
|
||||
},
|
||||
{ once: singleShot }
|
||||
);
|
||||
}
|
||||
|
||||
static dispatch(drawingsData: any /*TODO*/) {
|
||||
static dispatch(drawingsData: any, navpointData?: any /*TODO*/) {
|
||||
document.dispatchEvent(new CustomEvent(this.name, {detail: drawingsData}));
|
||||
if (DEBUG) console.log(`Event ${this.name} dispatched`);
|
||||
}
|
||||
|
||||
@ -103,20 +103,20 @@ export class DCSPolygon extends DCSDrawing {
|
||||
case "circle":
|
||||
// Example circle:
|
||||
/*
|
||||
colorString: 4278190335
|
||||
fillColorString: 4278190127
|
||||
lat: 27.65469131156049
|
||||
layer: "Blue"
|
||||
layerName: "Blue"
|
||||
lng: 54.33075915954884
|
||||
name: "SA11-2 + SA6-3"
|
||||
points: {0: {…}, x: 166867.07767244, y: -187576.93134045}
|
||||
polygonMode: "circle"
|
||||
primitiveType: "Polygon"
|
||||
radius: 36651.296128911
|
||||
style: "dash"
|
||||
thickness: 16
|
||||
visible: true*/
|
||||
colorString: 4278190335
|
||||
fillColorString: 4278190127
|
||||
lat: 27.65469131156049
|
||||
layer: "Blue"
|
||||
layerName: "Blue"
|
||||
lng: 54.33075915954884
|
||||
name: "SA11-2 + SA6-3"
|
||||
points: {0: {…}, x: 166867.07767244, y: -187576.93134045}
|
||||
polygonMode: "circle"
|
||||
primitiveType: "Polygon"
|
||||
radius: 36651.296128911
|
||||
style: "dash"
|
||||
thickness: 16
|
||||
visible: true*/
|
||||
|
||||
this.#polygon = new Circle([drawingData.lat, drawingData.lng], {
|
||||
radius: Math.round(drawingData.radius),
|
||||
@ -131,7 +131,7 @@ export class DCSPolygon extends DCSDrawing {
|
||||
|
||||
case "arrow":
|
||||
let weight = this.getWeight();
|
||||
|
||||
|
||||
if (!weight || weight < 1) {
|
||||
weight = 1;
|
||||
}
|
||||
@ -160,44 +160,44 @@ export class DCSPolygon extends DCSDrawing {
|
||||
|
||||
case "rect":
|
||||
/** Rectangle Example:
|
||||
* {
|
||||
"angle": 68.579040048342,
|
||||
"colorString": 255,
|
||||
"fillColorString": 4294901888,
|
||||
"height": 11100,
|
||||
"lat": 27.5547706075188,
|
||||
"layer": "Author",
|
||||
"layerName": "Author",
|
||||
"lng": 57.22438242806247,
|
||||
"mapX": 152970.68262179,
|
||||
"mapY": 97907.892121675,
|
||||
"name": "FLOT BUFFER EAST",
|
||||
"points": {
|
||||
"1": {
|
||||
"lat": 27.417344649833286,
|
||||
"lng": 57.34472624501578
|
||||
},
|
||||
"2": {
|
||||
"lat": 27.38096510320196,
|
||||
"lng": 57.24010993680159
|
||||
},
|
||||
"3": {
|
||||
"lat": 27.69209116201148,
|
||||
"lng": 57.1037392116416
|
||||
},
|
||||
"4": {
|
||||
"lat": 27.728570135811577,
|
||||
"lng": 57.20860735951096
|
||||
}
|
||||
},
|
||||
"polygonMode": "rect",
|
||||
"primitiveType": "Polygon",
|
||||
"style": "dot",
|
||||
"thickness": 16,
|
||||
"visible": true,
|
||||
"width": 37000
|
||||
}
|
||||
*/
|
||||
* {
|
||||
"angle": 68.579040048342,
|
||||
"colorString": 255,
|
||||
"fillColorString": 4294901888,
|
||||
"height": 11100,
|
||||
"lat": 27.5547706075188,
|
||||
"layer": "Author",
|
||||
"layerName": "Author",
|
||||
"lng": 57.22438242806247,
|
||||
"mapX": 152970.68262179,
|
||||
"mapY": 97907.892121675,
|
||||
"name": "FLOT BUFFER EAST",
|
||||
"points": {
|
||||
"1": {
|
||||
"lat": 27.417344649833286,
|
||||
"lng": 57.34472624501578
|
||||
},
|
||||
"2": {
|
||||
"lat": 27.38096510320196,
|
||||
"lng": 57.24010993680159
|
||||
},
|
||||
"3": {
|
||||
"lat": 27.69209116201148,
|
||||
"lng": 57.1037392116416
|
||||
},
|
||||
"4": {
|
||||
"lat": 27.728570135811577,
|
||||
"lng": 57.20860735951096
|
||||
}
|
||||
},
|
||||
"polygonMode": "rect",
|
||||
"primitiveType": "Polygon",
|
||||
"style": "dot",
|
||||
"thickness": 16,
|
||||
"visible": true,
|
||||
"width": 37000
|
||||
}
|
||||
*/
|
||||
const bounds = [
|
||||
[drawingData.points["1"].lat, drawingData.points["1"].lng],
|
||||
[drawingData.points["2"].lat, drawingData.points["2"].lng],
|
||||
@ -217,42 +217,42 @@ export class DCSPolygon extends DCSDrawing {
|
||||
|
||||
case "oval":
|
||||
/**
|
||||
* Example:
|
||||
* {
|
||||
"angle": 270,
|
||||
"colorString": 255,
|
||||
"fillColorString": 4278190080,
|
||||
"lat": 25.032272009407105,
|
||||
"layer": "Blue",
|
||||
"layerName": "Blue",
|
||||
"lng": 55.36597899137401,
|
||||
"mapX": -125416.92956726,
|
||||
"mapY": -89103.936896595,
|
||||
"name": "AM OTP",
|
||||
"points": {
|
||||
"1": {
|
||||
"lat": 25.03332743167039,
|
||||
"lng": 55.34689257576858
|
||||
},
|
||||
"2": {
|
||||
"lat": 25.034529398092356,
|
||||
"lng": 55.348849087588164
|
||||
},
|
||||
...
|
||||
"24": {
|
||||
"lat": 25.032053589358366,
|
||||
"lng": 55.34623694782629
|
||||
}
|
||||
},
|
||||
"polygonMode": "oval",
|
||||
"primitiveType": "Polygon",
|
||||
"r1": 1992.4714734497,
|
||||
"r2": 541.99904672895,
|
||||
"style": "dot",
|
||||
"thickness": 10,
|
||||
"visible": true
|
||||
}
|
||||
*/
|
||||
* Example:
|
||||
* {
|
||||
"angle": 270,
|
||||
"colorString": 255,
|
||||
"fillColorString": 4278190080,
|
||||
"lat": 25.032272009407105,
|
||||
"layer": "Blue",
|
||||
"layerName": "Blue",
|
||||
"lng": 55.36597899137401,
|
||||
"mapX": -125416.92956726,
|
||||
"mapY": -89103.936896595,
|
||||
"name": "AM OTP",
|
||||
"points": {
|
||||
"1": {
|
||||
"lat": 25.03332743167039,
|
||||
"lng": 55.34689257576858
|
||||
},
|
||||
"2": {
|
||||
"lat": 25.034529398092356,
|
||||
"lng": 55.348849087588164
|
||||
},
|
||||
...
|
||||
"24": {
|
||||
"lat": 25.032053589358366,
|
||||
"lng": 55.34623694782629
|
||||
}
|
||||
},
|
||||
"polygonMode": "oval",
|
||||
"primitiveType": "Polygon",
|
||||
"r1": 1992.4714734497,
|
||||
"r2": 541.99904672895,
|
||||
"style": "dot",
|
||||
"thickness": 10,
|
||||
"visible": true
|
||||
}
|
||||
*/
|
||||
const points: [number, number][] = Object.values(drawingData.points as Record<string, { lat: number; lng: number }>).map((p) => [p.lat, p.lng]);
|
||||
|
||||
this.#polygon = new Polygon(points, {
|
||||
@ -276,8 +276,8 @@ export class DCSPolygon extends DCSDrawing {
|
||||
dashArray: dashArray,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -374,21 +374,21 @@ export class DCSTextBox extends DCSDrawing {
|
||||
super(drawingData, parent);
|
||||
|
||||
/* Example textbox "ABC625":
|
||||
angle: 0
|
||||
borderThickness: 1
|
||||
colorString: 4294967295
|
||||
fillColorString: 8421504
|
||||
font: "DejaVuLGCSansCondensed.ttf"
|
||||
fontSize: 10
|
||||
layer: "Common"
|
||||
layerName: "Common"
|
||||
mapX: -261708.68309463
|
||||
mapY: -217863.03743212
|
||||
name: "ABC625"
|
||||
primitiveType: "TextBox"
|
||||
text: "ABC625"
|
||||
visible: true
|
||||
*/
|
||||
angle: 0
|
||||
borderThickness: 1
|
||||
colorString: 4294967295
|
||||
fillColorString: 8421504
|
||||
font: "DejaVuLGCSansCondensed.ttf"
|
||||
fontSize: 10
|
||||
layer: "Common"
|
||||
layerName: "Common"
|
||||
mapX: -261708.68309463
|
||||
mapY: -217863.03743212
|
||||
name: "ABC625"
|
||||
primitiveType: "TextBox"
|
||||
text: "ABC625"
|
||||
visible: true
|
||||
*/
|
||||
const customIcon = new DivIcon({
|
||||
html: `
|
||||
<div style="
|
||||
@ -527,9 +527,6 @@ export class DCSDrawingsContainer {
|
||||
initFromData(drawingsData) {
|
||||
let hasContainers = false;
|
||||
Object.keys(drawingsData).forEach((layerName: string) => {
|
||||
if (layerName === 'navpoints') {
|
||||
return;
|
||||
}
|
||||
if (drawingsData[layerName]["name"] === undefined && drawingsData[layerName]["callsignStr"] === undefined) {
|
||||
const newContainer = new DCSDrawingsContainer(layerName, this);
|
||||
this.addSubContainer(newContainer);
|
||||
@ -585,11 +582,11 @@ export class DCSDrawingsContainer {
|
||||
if (othersContainer.getDrawings().length === 0) this.removeSubContainer(othersContainer); // Remove empty container
|
||||
}
|
||||
|
||||
initNavpoints(drawingsData) {
|
||||
const newContainer = new DCSDrawingsContainer('Navpoints', this);
|
||||
this.addSubContainer(newContainer);
|
||||
newContainer.initFromData(drawingsData);
|
||||
}
|
||||
// initNavpoints(drawingsData) {
|
||||
// const newContainer = new DCSDrawingsContainer('Navpoints', this);
|
||||
// this.addSubContainer(newContainer);
|
||||
// newContainer.initFromData(drawingsData);
|
||||
// }
|
||||
|
||||
getLayerGroup() {
|
||||
return this.#layerGroup;
|
||||
@ -703,6 +700,7 @@ export class DCSDrawingsContainer {
|
||||
|
||||
export class DrawingsManager {
|
||||
#drawingsContainer: DCSDrawingsContainer;
|
||||
#navpointsContainer: DCSDrawingsContainer;
|
||||
#updateEventRequested: boolean = false;
|
||||
#sessionDataDrawings = {};
|
||||
#initialized: boolean = false;
|
||||
@ -711,6 +709,7 @@ export class DrawingsManager {
|
||||
const drawingsLayerGroup = new LayerGroup();
|
||||
drawingsLayerGroup.addTo(getApp().getMap());
|
||||
this.#drawingsContainer = new DCSDrawingsContainer("Mission drawings", drawingsLayerGroup);
|
||||
this.#navpointsContainer = new DCSDrawingsContainer("Navpoints", drawingsLayerGroup);
|
||||
|
||||
MapOptionsChangedEvent.on((mapOptions: MapOptions) => {
|
||||
this.#drawingsContainer.setVisibility(mapOptions.showMissionDrawings);
|
||||
@ -718,18 +717,24 @@ export class DrawingsManager {
|
||||
|
||||
SessionDataLoadedEvent.on((sessionData) => {
|
||||
this.#sessionDataDrawings = sessionData.drawings ?? {};
|
||||
if (this.#initialized) if (this.#sessionDataDrawings["Mission drawings"]) this.#drawingsContainer.fromJSON(this.#sessionDataDrawings["Mission drawings"]);
|
||||
if (this.#initialized) {
|
||||
if (this.#sessionDataDrawings["Mission drawings"]) this.#drawingsContainer.fromJSON(this.#sessionDataDrawings["Mission drawings"]);
|
||||
if (this.#sessionDataDrawings["Navpoints"]) this.#navpointsContainer.fromJSON(this.#sessionDataDrawings["Navpoints"]);
|
||||
}
|
||||
this.#drawingsContainer.setVisibility(getApp().getMap().getOptions().showMissionDrawings);
|
||||
});
|
||||
}
|
||||
|
||||
initDrawings(data: { drawings: Record<string, Record<string, any>> }): boolean {
|
||||
if (data && data.drawings) {
|
||||
if (data.drawings.navpoints) {
|
||||
this.#navpointsContainer.initFromData(data.drawings.navpoints);
|
||||
delete data.drawings.navpoints;
|
||||
}
|
||||
this.#drawingsContainer.initFromData(data.drawings);
|
||||
if (data.drawings.navpoints) this.#drawingsContainer.initNavpoints(data.drawings.navpoints);
|
||||
if (this.#sessionDataDrawings["Mission drawings"]) this.#drawingsContainer.fromJSON(this.#sessionDataDrawings["Mission drawings"]);
|
||||
this.#drawingsContainer.setVisibility(getApp().getMap().getOptions().showMissionDrawings);
|
||||
DrawingsInitEvent.dispatch(this.#drawingsContainer);
|
||||
DrawingsInitEvent.dispatch(this.#drawingsContainer, this.#navpointsContainer);
|
||||
this.#initialized = true;
|
||||
return true;
|
||||
} else {
|
||||
@ -742,6 +747,10 @@ export class DrawingsManager {
|
||||
return this.#drawingsContainer;
|
||||
}
|
||||
|
||||
getNavpointsContainer() {
|
||||
return this.#navpointsContainer;
|
||||
}
|
||||
|
||||
requestUpdateEventDispatch() {
|
||||
if (this.#updateEventRequested) return;
|
||||
this.#updateEventRequested = true;
|
||||
|
||||
@ -14,7 +14,7 @@ import { OlRangeSlider } from "../components/olrangeslider";
|
||||
import { CoalitionCircle } from "../../map/coalitionarea/coalitioncircle";
|
||||
import { DrawSubState, ERAS_ORDER, IADSTypes, NO_SUBSTATE, OlympusState, OlympusSubState } from "../../constants/constants";
|
||||
import { AppStateChangedEvent, CoalitionAreasChangedEvent, CoalitionAreaSelectedEvent, DrawingsInitEvent, DrawingsUpdatedEvent } from "../../events";
|
||||
import { FaXmark } from "react-icons/fa6";
|
||||
import { FaCopy, FaPencil, FaRegCompass, FaXmark } from "react-icons/fa6";
|
||||
import { deepCopyTable } from "../../other/utils";
|
||||
import { DCSDrawingsContainer, DCSEmptyLayer } from "../../map/drawings/drawingsmanager";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
@ -35,6 +35,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
|
||||
const [openContainers, setOpenContainers] = useState([] as DCSDrawingsContainer[]);
|
||||
const [mainDrawingsContainer, setDrawingsContainer] = useState({ container: null } as { container: null | DCSDrawingsContainer });
|
||||
const [navpointsContainer, setNavpointsContainer] = useState({ container: null } as { container: null | DCSDrawingsContainer });
|
||||
const [searchString, setSearchString] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
@ -42,11 +43,13 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
setAppState(state);
|
||||
setAppSubState(subState);
|
||||
});
|
||||
DrawingsInitEvent.on((drawingContainer) => {
|
||||
DrawingsInitEvent.on((drawingContainer, navpointsContainer) => {
|
||||
setDrawingsContainer({ container: drawingContainer });
|
||||
setNavpointsContainer({ container: navpointsContainer });
|
||||
});
|
||||
DrawingsUpdatedEvent.on(() => {
|
||||
setDrawingsContainer({ container: getApp().getDrawingsManager().getDrawingsContainer() });
|
||||
setNavpointsContainer({ container: getApp().getDrawingsManager().getNavpointsContainer() });
|
||||
});
|
||||
}, []);
|
||||
|
||||
@ -179,12 +182,9 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
You can change the name and the coalition of the area. You can also generate an IADS area by selecting the types, eras, and ranges of units you
|
||||
want to include in the area. You can also set the density and distribution of the IADS. If you check the 'Force coalition appropriate units' box,
|
||||
the IADS will only include units that are appropriate for the coalition of the area (e.g. Hawk SAMs for {""}
|
||||
<span className="text-blue-500">blue</span> and SA-6 SAMs for{" "}
|
||||
<span
|
||||
className={`text-red-500`}
|
||||
>
|
||||
red
|
||||
</span>
|
||||
<span className="text-blue-500">blue</span> and SA-6 SAMs for <span className={`
|
||||
text-red-500
|
||||
`}>red</span>
|
||||
).
|
||||
</div>
|
||||
<div>
|
||||
@ -199,9 +199,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
<div>
|
||||
You can search for a specific drawing by typing in the search bar. The search is case-insensitive and will match any part of the drawing name.
|
||||
</div>
|
||||
<div>
|
||||
Any change you make is persistent and will be saved for the next time you reload Olympus, as long as the DCS mission was not restarted.
|
||||
</div>
|
||||
<div>Any change you make is persistent and will be saved for the next time you reload Olympus, as long as the DCS mission was not restarted.</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
@ -279,10 +277,40 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
|
||||
<div>
|
||||
<div className="flex flex-col gap-2 p-6">
|
||||
<div className="text-sm text-gray-400">Mission drawings</div>
|
||||
<div
|
||||
className={`flex flex-row items-center text-sm text-gray-400`}
|
||||
>
|
||||
<span
|
||||
className={`
|
||||
mr-2 px-1 py-1 text-center font-bold text-olympus-700
|
||||
text-white
|
||||
`}
|
||||
>
|
||||
<FaPencil />
|
||||
</span>
|
||||
Mission drawings
|
||||
</div>
|
||||
<OlSearchBar onChange={(search) => setSearchString(search)} text={searchString || ""}></OlSearchBar>
|
||||
<div className="flex flex-col gap-2">{mainDrawingsContainer.container && renderDrawingsContainerControls(mainDrawingsContainer.container)}</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2 p-6">
|
||||
<div
|
||||
className={`flex flex-row items-center text-sm text-gray-400`}
|
||||
>
|
||||
<span
|
||||
className={`
|
||||
mr-2 px-1 py-1 text-center font-bold text-olympus-700
|
||||
text-white
|
||||
`}
|
||||
>
|
||||
<FaRegCompass />
|
||||
</span>
|
||||
Navpoints
|
||||
</div>
|
||||
<OlSearchBar onChange={(search) => setSearchString(search)} text={searchString || ""}></OlSearchBar>
|
||||
<div className="flex flex-col gap-2">{navpointsContainer.container && renderDrawingsContainerControls(navpointsContainer.container)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -349,9 +377,11 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
bg-olympus-600 p-5
|
||||
`}
|
||||
>
|
||||
<div className={`
|
||||
border-b-2 border-b-olympus-100 pb-4 text-gray-300
|
||||
`}>Automatic IADS generation</div>
|
||||
<div
|
||||
className={`border-b-2 border-b-olympus-100 pb-4 text-gray-300`}
|
||||
>
|
||||
Automatic IADS generation
|
||||
</div>
|
||||
<OlDropdown className="" label="Units types" disableAutoClose={true}>
|
||||
{types.map((type, idx) => {
|
||||
if (!(type in typesSelection)) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user