mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat: added grouped path markers
fix: fixed shortcuts getting stuck
This commit is contained in:
parent
52606b8d57
commit
1deeaacf1d
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="41"
|
||||
height="51"
|
||||
viewBox="0 0 41 51"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
@ -22,10 +22,10 @@
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="15.941176"
|
||||
inkscape:cx="20.48155"
|
||||
inkscape:cy="25.5"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:cx="20.512916"
|
||||
inkscape:cy="25.500001"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1369"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
@ -33,7 +33,7 @@
|
||||
<g
|
||||
filter="url(#filter0_d_1082_10311)"
|
||||
id="g3"
|
||||
transform="translate(2.0701107,2.0701107)">
|
||||
transform="matrix(0.65082874,0,0,0.65082874,3.8892989,2.018336)">
|
||||
<mask
|
||||
id="path-1-outside-1_1082_10311"
|
||||
maskUnits="userSpaceOnUse"
|
||||
@ -70,7 +70,7 @@
|
||||
x="0"
|
||||
y="0.75"
|
||||
width="40.5"
|
||||
height="49.9443"
|
||||
height="49.944302"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB">
|
||||
<feFlood
|
||||
|
||||
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
30
frontend/react/src/map/markers/pathmarker.ts
Normal file
30
frontend/react/src/map/markers/pathmarker.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { DivIcon, LatLngExpression, Map, MarkerOptions } from "leaflet";
|
||||
import { CustomMarker } from "./custommarker";
|
||||
import { SVGInjector } from "@tanem/svg-injector";
|
||||
|
||||
export class PathMarker extends CustomMarker {
|
||||
constructor(latlng: LatLngExpression, options?: MarkerOptions) {
|
||||
super(latlng, options);
|
||||
this.options.interactive = true;
|
||||
this.options.draggable = true;
|
||||
this.setZIndexOffset(9999);
|
||||
}
|
||||
|
||||
createIcon() {
|
||||
this.setIcon(
|
||||
new DivIcon({
|
||||
iconSize: [32, 32],
|
||||
iconAnchor: [16, 27],
|
||||
className: "leaflet-path-marker",
|
||||
})
|
||||
);
|
||||
var el = document.createElement("div");
|
||||
el.classList.add("ol-path-icon");
|
||||
var img = document.createElement("img");
|
||||
img.src = "images/markers/path.svg";
|
||||
img.onload = () => SVGInjector(img);
|
||||
|
||||
el.appendChild(img);
|
||||
this.getElement()?.appendChild(el);
|
||||
}
|
||||
}
|
||||
@ -13,14 +13,18 @@ export class Shortcut {
|
||||
this.#id = id;
|
||||
this.#options = options;
|
||||
|
||||
AppStateChangedEvent.on((state, subState) => (this.#keydown = false));
|
||||
ModalEvent.on((modal) => (this.#modal = modal))
|
||||
/* I don't know why I set this, may be a leftover from initial shortcut experiments.
|
||||
If enabled, it will cause the keydown to be reset when the app state changes, which may
|
||||
cause shortcuts that cause a state change (like unit selection) to remain stuck. */
|
||||
//AppStateChangedEvent.on((state, subState) => (this.#keydown = false));
|
||||
|
||||
ModalEvent.on((modal) => (this.#modal = modal));
|
||||
|
||||
/* On keyup, it is enough to check the code only, not the entire combination */
|
||||
document.addEventListener("keyup", (ev: any) => {
|
||||
if (this.#modal) return;
|
||||
if (this.#keydown && this.getOptions().code === ev.code) {
|
||||
console.log(`Keyup for shortcut ${this.#id}`)
|
||||
console.log(`Keyup for shortcut ${this.#id}`);
|
||||
ev.preventDefault();
|
||||
this.#keydown = false;
|
||||
this.getOptions().keyUpCallback(ev);
|
||||
@ -30,7 +34,7 @@ export class Shortcut {
|
||||
/* Forced keyup, in case the window loses focus */
|
||||
document.addEventListener("blur", (ev: any) => {
|
||||
if (this.#keydown) {
|
||||
console.log(`Keyup (forced by blur) for shortcut ${this.#id}`)
|
||||
console.log(`Keyup (forced by blur) for shortcut ${this.#id}`);
|
||||
ev.preventDefault();
|
||||
this.#keydown = false;
|
||||
this.getOptions().keyUpCallback(ev);
|
||||
@ -46,10 +50,10 @@ export class Shortcut {
|
||||
(this.getOptions().ctrlKey === undefined || ev.ctrlKey === (this.getOptions().ctrlKey ?? ev.code.indexOf("Control") >= 0)) &&
|
||||
(this.getOptions().shiftKey === undefined || ev.shiftKey === (this.getOptions().shiftKey ?? ev.code.indexOf("Shift") >= 0))
|
||||
) {
|
||||
console.log(`Keydown event for shortcut ${this.#id}`)
|
||||
console.log(`Keydown event for shortcut ${this.#id}`);
|
||||
ev.preventDefault();
|
||||
this.#keydown = true;
|
||||
const keyDownCallback = this.getOptions().keyDownCallback
|
||||
const keyDownCallback = this.getOptions().keyDownCallback;
|
||||
if (keyDownCallback) keyDownCallback(ev); /* Key down event is optional */
|
||||
}
|
||||
});
|
||||
@ -84,4 +88,8 @@ export class Shortcut {
|
||||
);
|
||||
return actions;
|
||||
}
|
||||
|
||||
#setKeydown(keydown: boolean) {
|
||||
this.#keydown = keydown;
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,15 +72,9 @@ import { ArrowMarker } from "../map/markers/arrowmarker";
|
||||
import { Spot } from "../mission/spot";
|
||||
import { SpotEditMarker } from "../map/markers/spoteditmarker";
|
||||
import { SpotMarker } from "../map/markers/spotmarker";
|
||||
import { get } from "http";
|
||||
|
||||
const bearingStrings = ["north", "north-east", "east", "south-east", "south", "south-west", "west", "north-west", "north"];
|
||||
|
||||
var pathIcon = new Icon({
|
||||
iconUrl: "images/markers/path.svg",
|
||||
iconAnchor: [20, 43],
|
||||
});
|
||||
|
||||
/**
|
||||
* Unit class which controls unit behaviour
|
||||
*/
|
||||
@ -164,7 +158,6 @@ export abstract class Unit extends CustomMarker {
|
||||
#selected: boolean = false;
|
||||
#hidden: boolean = false;
|
||||
#highlighted: boolean = false;
|
||||
#pathMarkers: Marker[] = [];
|
||||
#pathPolyline: Polyline;
|
||||
#contactsPolylines: Polyline[] = [];
|
||||
#engagementCircle: RangeCircle;
|
||||
@ -1223,14 +1216,6 @@ export abstract class Unit extends CustomMarker {
|
||||
if (!this.#human) this.#activePath = [];
|
||||
}
|
||||
|
||||
updatePathFromMarkers() {
|
||||
var path: any = [];
|
||||
this.#pathMarkers.forEach((marker) => {
|
||||
path[Object.keys(path).length.toString()] = marker.getLatLng();
|
||||
});
|
||||
getApp().getServerManager().addDestination(this.ID, path);
|
||||
}
|
||||
|
||||
attackUnit(targetID: number) {
|
||||
/* Units can't attack themselves */
|
||||
if (!this.#human) if (this.ID != targetID) getApp().getServerManager().attackUnit(this.ID, targetID);
|
||||
@ -1716,37 +1701,8 @@ export abstract class Unit extends CustomMarker {
|
||||
var points: LatLng[] = [];
|
||||
points.push(new LatLng(this.#position.lat, this.#position.lng));
|
||||
|
||||
/* Add markers if missing */
|
||||
while (this.#pathMarkers.length < Object.keys(this.#activePath).length) {
|
||||
var marker = new Marker([0, 0], {
|
||||
icon: pathIcon,
|
||||
draggable: true,
|
||||
}).addTo(getApp().getMap());
|
||||
marker.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
});
|
||||
marker.on("dragend", (event) => {
|
||||
this.updatePathFromMarkers();
|
||||
event.target.options["freeze"] = false;
|
||||
});
|
||||
this.#pathMarkers.push(marker);
|
||||
}
|
||||
|
||||
/* Remove markers if too many */
|
||||
while (this.#pathMarkers.length > Object.keys(this.#activePath).length) {
|
||||
getApp()
|
||||
.getMap()
|
||||
.removeLayer(this.#pathMarkers[this.#pathMarkers.length - 1]);
|
||||
this.#pathMarkers.splice(this.#pathMarkers.length - 1, 1);
|
||||
}
|
||||
|
||||
/* Update the position of the existing markers (to avoid creating markers uselessly) */
|
||||
for (let WP in this.#activePath) {
|
||||
var destination = this.#activePath[WP];
|
||||
var frozen = this.#pathMarkers[parseInt(WP)].options["freeze"];
|
||||
if (!frozen) {
|
||||
this.#pathMarkers[parseInt(WP)].setLatLng([destination.lat, destination.lng]);
|
||||
}
|
||||
points.push(new LatLng(destination.lat, destination.lng));
|
||||
}
|
||||
|
||||
@ -1763,10 +1719,6 @@ export abstract class Unit extends CustomMarker {
|
||||
|
||||
#clearPath() {
|
||||
if (this.#pathPolyline.getLatLngs().length != 0) {
|
||||
for (let WP in this.#pathMarkers) {
|
||||
getApp().getMap().removeLayer(this.#pathMarkers[WP]);
|
||||
}
|
||||
this.#pathMarkers = [];
|
||||
this.#pathPolyline.setLatLngs([]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ import {
|
||||
} from "../events";
|
||||
import { UnitDatabase } from "./databases/unitdatabase";
|
||||
import * as turf from "@turf/turf";
|
||||
import { PathMarker } from "../map/markers/pathmarker";
|
||||
|
||||
/** The UnitsManager handles the creation, update, and control of units. Data is strictly updated by the server ONLY. This means that any interaction from the user will always and only
|
||||
* result in a command to the server, executed by means of a REST PUT request. Any subsequent change in data will be reflected only when the new data is sent back by the server. This strategy allows
|
||||
@ -54,6 +55,7 @@ export class UnitsManager {
|
||||
#protectionCallback: (units: Unit[]) => void = (units) => {};
|
||||
#AWACSReference: Unit | null = null;
|
||||
#clusters: { [key: number]: Unit[] } = {};
|
||||
#pathMarkers: PathMarker[] = [];
|
||||
|
||||
constructor() {
|
||||
this.#unitDatabase = new UnitDatabase();
|
||||
@ -303,8 +305,50 @@ export class UnitsManager {
|
||||
}
|
||||
|
||||
/* Update all the lines of all the selected units. This code is handled by the UnitsManager since, for example, it must be run both when the detected OR the detecting unit is updated */
|
||||
let pathMarkersCoordinates: LatLng[] = [];
|
||||
for (let ID in this.#units) {
|
||||
if (this.#units[ID].getSelected()) this.#units[ID].drawLines();
|
||||
if (this.#units[ID].getSelected()) {
|
||||
this.#units[ID].drawLines();
|
||||
const unitPath = this.#units[ID].getActivePath();
|
||||
unitPath.forEach((latlng: LatLng) => {
|
||||
if (pathMarkersCoordinates.every((coord: LatLng) => coord.lat != latlng.lat && coord.lng != latlng.lng)) pathMarkersCoordinates.push(latlng);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the path markers */
|
||||
if (this.#pathMarkers.find((pathMarker: PathMarker) => pathMarker.options["freeze"]) === undefined) {
|
||||
this.#pathMarkers.forEach((pathMarker: PathMarker) => {
|
||||
if (!pathMarkersCoordinates.some((coord: LatLng) => pathMarker.getLatLng().equals(coord))) {
|
||||
pathMarker.remove();
|
||||
this.#pathMarkers = this.#pathMarkers.filter((marker: PathMarker) => marker !== pathMarker);
|
||||
}
|
||||
});
|
||||
|
||||
pathMarkersCoordinates.forEach((latlng: LatLng) => {
|
||||
if (!this.#pathMarkers.some((pathMarker: PathMarker) => pathMarker.getLatLng().equals(latlng))) {
|
||||
const pathMarker = new PathMarker(latlng);
|
||||
|
||||
pathMarker.on("dragstart", (event) => {
|
||||
event.target.options["freeze"] = true;
|
||||
event.target.options["originalPosition"] = event.target.getLatLng();
|
||||
});
|
||||
pathMarker.on("dragend", (event) => {
|
||||
event.target.options["freeze"] = false;
|
||||
this.getSelectedUnits().forEach((unit) => {
|
||||
let path = [...unit.getActivePath()];
|
||||
const idx = path.findIndex((coord: LatLng) => coord.equals(event.target.options["originalPosition"]));
|
||||
if (idx !== -1) {
|
||||
path[idx] = event.target.getLatLng();
|
||||
getApp().getServerManager().addDestination(unit.ID, path);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
pathMarker.addTo(getApp().getMap());
|
||||
this.#pathMarkers.push(pathMarker);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Compute the base clusters */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user