Merge branch 'main' into 358-right-click-long-press-for-unit-action-context-menu

This commit is contained in:
Pax1601
2023-08-30 09:13:06 +02:00
committed by GitHub
12 changed files with 442 additions and 117 deletions

View File

@@ -15,7 +15,7 @@ const DEMO_UNIT_DATA = {
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 }, radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false }, generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ], ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ],
contacts: [{ID: 2, detectionMethod: 1}, {ID: 3, detectionMethod: 4}], contacts: [{ID: 2, detectionMethod: 1}, {ID: 3, detectionMethod: 4}, {ID: 5, detectionMethod: 4}],
activePath: [{lat: 38, lng: -115, alt: 0}, {lat: 38, lng: -114, alt: 0}] activePath: [{lat: 38, lng: -115, alt: 0}, {lat: 38, lng: -114, alt: 0}]
}, },
["2"]:{ category: "Aircraft", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "FA-18C_hornet", unitName: "Cool guy 1-2", groupName: "Cool group 2", state: 1, task: "Being cool", ["2"]:{ category: "Aircraft", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "FA-18C_hornet", unitName: "Cool guy 1-2", groupName: "Cool group 2", state: 1, task: "Being cool",

View File

@@ -1031,13 +1031,41 @@ nav.ol-panel> :last-child {
} }
.ol-target-icon { .ol-target-icon {
background-image: url("/resources/theme/images/markers/target.svg");
height: 52px; height: 52px;
pointer-events: none; pointer-events: none;
width: 52px; width: 52px;
z-index: 9999; z-index: 9999;
} }
.ol-smoke-icon {
background-image: url("/resources/theme/images/markers/smoke.svg");
height: 52px;
pointer-events: none;
width: 52px;
z-index: 9999;
opacity: 0.8;
}
.ol-smoke-icon[data-color="white"] {
fill: white;
}
.ol-smoke-icon[data-color="blue"] {
fill: blue;
}
.ol-smoke-icon[data-color="red"] {
fill: red;
}
.ol-smoke-icon[data-color="green"] {
fill: green;
}
.ol-smoke-icon[data-color="orange"] {
fill: orange;
}
.ol-draw-icon { .ol-draw-icon {
background-image: url("/resources/theme/images/markers/draw.svg"); background-image: url("/resources/theme/images/markers/draw.svg");
height: 24px; height: 24px;

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="52"
height="52"
viewBox="0 0 13.758333 13.758333"
version="1.1"
id="svg5"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
sodipodi:docname="smoke.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
width="52mm"
units="px"
inkscape:zoom="1.4823794"
inkscape:cx="-107.59729"
inkscape:cy="-51.268927"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<defs
id="defs2">
<linearGradient
id="linearGradient4717"
inkscape:swatch="solid">
<stop
style="stop-color:#0cffff;stop-opacity:1;"
offset="0"
id="stop4715" />
</linearGradient>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<circle
style="stroke-width:13.3879;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901"
cx="6.3892984"
cy="12.526179"
r="0.40000001" />
<circle
style="stroke-width:21.3082;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-1"
cx="6.1684337"
cy="11.768929"
r="0.63664067" />
<circle
style="stroke-width:28.7005;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-5"
cx="7.067668"
cy="11.674273"
r="0.85750532" />
<circle
style="stroke-width:28.1725;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-4"
cx="6.8468037"
cy="10.711934"
r="0.84172928" />
<circle
style="stroke-width:51.9334;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-6"
cx="8.7714815"
cy="8.3928556"
r="1.5516512" />
<circle
style="stroke-width:41.373;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-2"
cx="7.9037986"
cy="10.159773"
r="1.2361304" />
<circle
style="stroke-width:53.5174;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-3"
cx="7.320085"
cy="7.6040535"
r="1.5989795" />
<circle
style="fill-opacity:1;stroke:none;stroke-width:53.5174;stroke-linecap:round;stroke-opacity:1"
id="path901-3-9"
cx="7.05018"
cy="9.5266676"
r="1.5989795" />
<circle
style="stroke-width:60.3817;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-20"
cx="10.033565"
cy="6.5155067"
r="1.804068" />
<circle
style="stroke-width:60.9097;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-15"
cx="8.0300064"
cy="4.9221258"
r="1.819844" />
<circle
style="stroke-width:56.6856;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-0"
cx="11.800482"
cy="2.3821828"
r="1.6936357" />
<circle
style="stroke-width:56.1575;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-0-9"
cx="11.3272"
cy="4.7801414"
r="1.6778597" />
<circle
style="stroke-width:68.302;stroke-linecap:round;stroke:none;stroke-opacity:1;fill-opacity:1"
id="path901-0-4"
cx="9.8600283"
cy="2.6345997"
r="2.0407088" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="52"
height="52"
viewBox="0 0 13.758333 13.758333"
version="1.1"
id="svg5"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
sodipodi:docname="target.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
width="52mm"
units="px"
inkscape:zoom="16.771208"
inkscape:cx="31.989348"
inkscape:cy="27.63665"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2">
<linearGradient
id="linearGradient4717"
inkscape:swatch="solid">
<stop
style="stop-color:#0cffff;stop-opacity:1;"
offset="0"
id="stop4715" />
</linearGradient>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<ellipse
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.03188;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="path5477"
cx="6.8599777"
cy="6.8209338"
rx="1.9410306"
ry="1.948356" />
<rect
style="fill:#ff5858;fill-opacity:1;stroke:#ffffff;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect3980"
width="0.54935014"
height="2.6236348"
x="6.5846372"
y="3.3855996"
rx="0.29515001" />
<rect
style="fill:#ff5858;fill-opacity:1;stroke:#ffffff;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect3980-4"
width="0.54935014"
height="2.6236348"
x="6.5858645"
y="7.6347723"
rx="0.29515001" />
<rect
style="fill:#ff5858;fill-opacity:1;stroke:#ffffff;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect3980-47"
width="0.54935014"
height="2.6236348"
x="6.5517845"
y="-10.252322"
rx="0.29515001"
transform="rotate(90)" />
<rect
style="fill:#ff5858;fill-opacity:1;stroke:#ffffff;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect3980-4-3"
width="0.54935014"
height="2.6236348"
x="6.5530119"
y="-6.003149"
rx="0.29515001"
transform="rotate(90)" />
<ellipse
style="fill:none;fill-opacity:1;stroke:#ff5858;stroke-width:0.449792;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="path5477-2"
cx="6.8613305"
cy="6.8167095"
rx="1.9410306"
ry="1.948356" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -19,7 +19,7 @@ interface CustomEventMap {
"mapStateChanged": CustomEvent<string>, "mapStateChanged": CustomEvent<string>,
"mapContextMenu": CustomEvent<>, "mapContextMenu": CustomEvent<>,
"mapVisibilityOptionsChanged": CustomEvent<>, "mapVisibilityOptionsChanged": CustomEvent<>,
"commandModeOptionsChanged": CustomEvent<>, "commandModeOptionsChanged": CustomEvent<>,
"contactsUpdated": CustomEvent<Unit>, "contactsUpdated": CustomEvent<Unit>,
} }

View File

@@ -138,15 +138,16 @@ export const MOVE_UNIT = "Move unit";
export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area"; export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area";
export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"]; export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"];
export const visibilityControlsTypes: string[][] = [["human"], ["dcs"], ["aircraft"], ["groundunit-sam", "groundunit-sam-radar", "groundunit-sam-launcher"], ["groundunit-other", "groundunit-ewr"], ["navyunit"], ["airbase"]]; export const visibilityControlsTypes: string[][] = [["human"], ["dcs"], ["aircraft"], ["groundunit-sam", "groundunit-sam-radar", "groundunit-sam-launcher"], ["groundunit-other", "groundunit-ewr"], ["navyunit"], ["airbase"]];
export const visibilityControlsTootlips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"]; export const visibilityControlsTooltips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"];
export const IADSTypes = ["AAA", "MANPADS", "SAM Site", "Radar"]; export const IADSTypes = ["AAA", "MANPADS", "SAM Site", "Radar"];
export const IADSDensities: {[key: string]: number}= {"AAA": 0.8, "MANPADS": 0.3, "SAM Site": 0.1, "Radar": 0.05}; export const IADSDensities: {[key: string]: number}= {"AAA": 0.8, "MANPADS": 0.3, "SAM Site": 0.1, "Radar": 0.05};
export const SHOW_CONTACT_LINES = "Show unit contact lines"; export const SHOW_CONTACT_LINES = "Show unit contact lines";
export const HIDE_GROUP_MEMBERS = "Hide group members when zoomed out"; export const HIDE_GROUP_MEMBERS = "Hide group members when zoomed out";
export const SHOW_UNIT_PATHS = "Show unit paths"; export const SHOW_UNIT_LABELS = "Show unit labels";
export const SHOW_UNIT_TARGETS = "Show unit targets"; export const SHOW_UNIT_PATHS = "Show unit paths";
export const SHOW_UNIT_TARGETS = "Show unit targets";
export enum DataIndexes { export enum DataIndexes {
startOfData = 0, startOfData = 0,

View File

@@ -12,6 +12,7 @@ import { ftToM } from "../other/utils";
import { GAME_MASTER } from "../constants/constants"; import { GAME_MASTER } from "../constants/constants";
import { navyUnitDatabase } from "../unit/navyunitdatabase"; import { navyUnitDatabase } from "../unit/navyunitdatabase";
import { CoalitionArea } from "../map/coalitionarea"; import { CoalitionArea } from "../map/coalitionarea";
import { SmokeMarker } from "../map/smokemarker";
export class MapContextMenu extends ContextMenu { export class MapContextMenu extends ContextMenu {
#coalitionSwitch: Switch; #coalitionSwitch: Switch;
@@ -158,6 +159,8 @@ export class MapContextMenu extends ContextMenu {
document.addEventListener("contextMenuDeploySmoke", (e: any) => { document.addEventListener("contextMenuDeploySmoke", (e: any) => {
this.hide(); this.hide();
spawnSmoke(e.detail.color, this.getLatLng()); spawnSmoke(e.detail.color, this.getLatLng());
var marker = new SmokeMarker(this.getLatLng(), e.detail.color);
marker.addTo(getMap());
}); });
document.addEventListener("contextMenuExplosion", (e: any) => { document.addEventListener("contextMenuExplosion", (e: any) => {

View File

@@ -137,9 +137,6 @@ function setupEvents() {
return; return;
} }
switch (ev.code) { switch (ev.code) {
case "KeyL":
document.body.toggleAttribute("data-hide-labels");
break;
case "KeyT": case "KeyT":
toggleDemoEnabled(); toggleDemoEnabled();
break; break;

View File

@@ -12,7 +12,7 @@ import { DestinationPreviewMarker } from "./destinationpreviewmarker";
import { TemporaryUnitMarker } from "./temporaryunitmarker"; import { TemporaryUnitMarker } from "./temporaryunitmarker";
import { ClickableMiniMap } from "./clickableminimap"; import { ClickableMiniMap } from "./clickableminimap";
import { SVGInjector } from '@tanem/svg-injector' import { SVGInjector } from '@tanem/svg-injector'
import { layers as mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, visibilityControls, visibilityControlsTootlips, MOVE_UNIT, SHOW_CONTACT_LINES, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, visibilityControlsTypes } from "../constants/constants"; import { layers as mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, visibilityControls, visibilityControlsTootlips, MOVE_UNIT, SHOW_CONTACT_LINES, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, visibilityControlsTypes, SHOW_UNIT_LABELS } from "../constants/constants";
import { TargetMarker } from "./targetmarker"; import { TargetMarker } from "./targetmarker";
import { CoalitionArea } from "./coalitionarea"; import { CoalitionArea } from "./coalitionarea";
import { CoalitionAreaContextMenu } from "../controls/coalitionareacontextmenu"; import { CoalitionAreaContextMenu } from "../controls/coalitionareacontextmenu";
@@ -65,7 +65,7 @@ export class Map extends L.Map {
#mapSourceDropdown: Dropdown; #mapSourceDropdown: Dropdown;
#mapVisibilityOptionsDropdown: Dropdown; #mapVisibilityOptionsDropdown: Dropdown;
#optionButtons: { [key: string]: HTMLButtonElement[] } = {} #optionButtons: { [key: string]: HTMLButtonElement[] } = {}
#visibiityOptions: { [key: string]: boolean } = {} #visibilityOptions: { [key: string]: boolean } = {}
constructor(ID: string) { constructor(ID: string) {
/* Init the leaflet map */ /* Init the leaflet map */
@@ -91,7 +91,7 @@ export class Map extends L.Map {
this.#mapSourceDropdown = new Dropdown("map-type", (layerName: string) => this.setLayer(layerName), this.getLayers()); this.#mapSourceDropdown = new Dropdown("map-type", (layerName: string) => this.setLayer(layerName), this.getLayers());
/* Visibility options dropdown */ /* Visibility options dropdown */
this.#mapVisibilityOptionsDropdown = new Dropdown("map-visibility-options", () => {}); this.#mapVisibilityOptionsDropdown = new Dropdown("map-visibility-options", (value: string) => { });
/* Init the state machine */ /* Init the state machine */
this.#state = IDLE; this.#state = IDLE;
@@ -151,6 +151,10 @@ export class Map extends L.Map {
this.#panToUnit(this.#centerUnit); this.#panToUnit(this.#centerUnit);
}); });
document.addEventListener("mapVisibilityOptionsChanged", () => {
this.getContainer().toggleAttribute("data-hide-labels", !this.getVisibilityOptions()[SHOW_UNIT_LABELS]);
});
/* Pan interval */ /* Pan interval */
this.#panInterval = window.setInterval(() => { this.#panInterval = window.setInterval(() => {
if (this.#panLeft || this.#panDown || this.#panRight || this.#panLeft) if (this.#panLeft || this.#panDown || this.#panRight || this.#panLeft)
@@ -161,19 +165,19 @@ export class Map extends L.Map {
/* Option buttons */ /* Option buttons */
this.#optionButtons["visibility"] = visibilityControls.map((option: string, index: number) => { this.#optionButtons["visibility"] = visibilityControls.map((option: string, index: number) => {
var typesArrayString = `"${visibilityControlsTypes[index][0]}"`; var typesArrayString = `"${visibilityControlsTypes[index][0]}"`;
visibilityControlsTypes[index].forEach((type: string, idx: number) => {if (idx > 0) typesArrayString = `${typesArrayString}, "${type}"`}); visibilityControlsTypes[index].forEach((type: string, idx: number) => { if (idx > 0) typesArrayString = `${typesArrayString}, "${type}"` });
return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, visibilityControlsTootlips[index], "toggleMarkerVisibility", `{"types": [${typesArrayString}]}`); return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, visibilityControlsTooltips[index], "toggleMarkerVisibility", `{"types": [${typesArrayString}]}`);
}); });
document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]); document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]);
/* Create the checkboxes to select the advanced visibility options */ /* Create the checkboxes to select the advanced visibility options */
this.#visibilityOptions[SHOW_CONTACT_LINES] = false;
this.#visibiityOptions[SHOW_CONTACT_LINES] = false; this.#visibilityOptions[HIDE_GROUP_MEMBERS] = true;
this.#visibiityOptions[HIDE_GROUP_MEMBERS] = true; this.#visibilityOptions[SHOW_UNIT_PATHS] = true;
this.#visibiityOptions[SHOW_UNIT_PATHS] = true; this.#visibilityOptions[SHOW_UNIT_TARGETS] = true;
this.#visibiityOptions[SHOW_UNIT_TARGETS] = true; this.#visibilityOptions[SHOW_UNIT_LABELS] = true;
this.#mapVisibilityOptionsDropdown.setOptionsElements(Object.keys(this.#visibiityOptions).map((option: string) => { this.#mapVisibilityOptionsDropdown.setOptionsElements(Object.keys(this.#visibilityOptions).map((option: string) => {
return createCheckboxOption(option, option, this.#visibiityOptions[option], (ev: any) => { return createCheckboxOption(option, option, this.#visibilityOptions[option], (ev: any) => {
this.#setVisibilityOption(option, ev); this.#setVisibilityOption(option, ev);
}); });
})); }));
@@ -436,7 +440,7 @@ export class Map extends L.Map {
} }
getVisibilityOptions() { getVisibilityOptions() {
return this.#visibiityOptions; return this.#visibilityOptions;
} }
/* Event handlers */ /* Event handlers */
@@ -704,7 +708,7 @@ export class Map extends L.Map {
else { else {
Object.values(getUnitsManager().selectedUnitsComputeGroupDestination(groupLatLng, this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => { Object.values(getUnitsManager().selectedUnitsComputeGroupDestination(groupLatLng, this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => {
if (idx < this.#destinationPreviewCursors.length) if (idx < this.#destinationPreviewCursors.length)
this.#destinationPreviewCursors[idx].setLatLng(this.#shiftKey? latlng : this.getMouseCoordinates()); this.#destinationPreviewCursors[idx].setLatLng(this.#shiftKey ? latlng : this.getMouseCoordinates());
}) })
}; };
} }
@@ -769,7 +773,7 @@ export class Map extends L.Map {
} }
#setVisibilityOption(option: string, ev: any) { #setVisibilityOption(option: string, ev: any) {
this.#visibiityOptions[option] = ev.currentTarget.checked; this.#visibilityOptions[option] = ev.currentTarget.checked;
document.dispatchEvent(new CustomEvent("mapVisibilityOptionsChanged")); document.dispatchEvent(new CustomEvent("mapVisibilityOptionsChanged"));
} }
} }

View File

@@ -0,0 +1,31 @@
import { DivIcon, LatLngExpression, MarkerOptions } from "leaflet";
import { CustomMarker } from "./custommarker";
import { SVGInjector } from "@tanem/svg-injector";
import { getMap } from "..";
export class SmokeMarker extends CustomMarker {
#color: string;
constructor(latlng: LatLngExpression, color: string, options?: MarkerOptions) {
super(latlng, options);
this.setZIndexOffset(9999);
this.#color = color;
window.setTimeout(() => { this.removeFrom(getMap()); }, 300000) /* Remove the smoke after 5 minutes */
}
createIcon() {
this.setIcon(new DivIcon({
iconSize: [52, 52],
iconAnchor: [26, 52],
className: "leaflet-smoke-marker",
}));
var el = document.createElement("div");
el.classList.add("ol-smoke-icon");
el.setAttribute("data-color", this.#color);
var img = document.createElement("img");
img.src = "/resources/theme/images/markers/smoke.svg";
img.onload = () => SVGInjector(img);
el.appendChild(img);
this.getElement()?.appendChild(el);
}
}

View File

@@ -94,43 +94,43 @@ export class Unit extends CustomMarker {
#hotgroup: number | null = null; #hotgroup: number | null = null;
#detectionMethods: number[] = []; #detectionMethods: number[] = [];
getAlive() {return this.#alive}; getAlive() { return this.#alive };
getHuman() {return this.#human}; getHuman() { return this.#human };
getControlled() {return this.#controlled}; getControlled() { return this.#controlled };
getCoalition() {return this.#coalition}; getCoalition() { return this.#coalition };
getCountry() {return this.#country}; getCountry() { return this.#country };
getName() {return this.#name}; getName() { return this.#name };
getUnitName() {return this.#unitName}; getUnitName() { return this.#unitName };
getGroupName() {return this.#groupName}; getGroupName() { return this.#groupName };
getState() {return this.#state}; getState() { return this.#state };
getTask() {return this.#task}; getTask() { return this.#task };
getHasTask() {return this.#hasTask}; getHasTask() { return this.#hasTask };
getPosition() {return this.#position}; getPosition() { return this.#position };
getSpeed() {return this.#speed}; getSpeed() { return this.#speed };
getHeading() {return this.#heading}; getHeading() { return this.#heading };
getIsTanker() {return this.#isTanker}; getIsTanker() { return this.#isTanker };
getIsAWACS() {return this.#isAWACS}; getIsAWACS() { return this.#isAWACS };
getOnOff() {return this.#onOff}; getOnOff() { return this.#onOff };
getFollowRoads() {return this.#followRoads}; getFollowRoads() { return this.#followRoads };
getFuel() {return this.#fuel}; getFuel() { return this.#fuel };
getDesiredSpeed() {return this.#desiredSpeed}; getDesiredSpeed() { return this.#desiredSpeed };
getDesiredSpeedType() {return this.#desiredSpeedType}; getDesiredSpeedType() { return this.#desiredSpeedType };
getDesiredAltitude() {return this.#desiredAltitude}; getDesiredAltitude() { return this.#desiredAltitude };
getDesiredAltitudeType() {return this.#desiredAltitudeType}; getDesiredAltitudeType() { return this.#desiredAltitudeType };
getLeaderID() {return this.#leaderID}; getLeaderID() { return this.#leaderID };
getFormationOffset() {return this.#formationOffset}; getFormationOffset() { return this.#formationOffset };
getTargetID() {return this.#targetID}; getTargetID() { return this.#targetID };
getTargetPosition() {return this.#targetPosition}; getTargetPosition() { return this.#targetPosition };
getROE() {return this.#ROE}; getROE() { return this.#ROE };
getReactionToThreat() {return this.#reactionToThreat}; getReactionToThreat() { return this.#reactionToThreat };
getEmissionsCountermeasures() {return this.#emissionsCountermeasures}; getEmissionsCountermeasures() { return this.#emissionsCountermeasures };
getTACAN() {return this.#TACAN}; getTACAN() { return this.#TACAN };
getRadio() {return this.#radio}; getRadio() { return this.#radio };
getGeneralSettings() {return this.#generalSettings}; getGeneralSettings() { return this.#generalSettings };
getAmmo() {return this.#ammo}; getAmmo() { return this.#ammo };
getContacts() {return this.#contacts}; getContacts() { return this.#contacts };
getActivePath() {return this.#activePath}; getActivePath() { return this.#activePath };
getIsLeader() {return this.#isLeader}; getIsLeader() { return this.#isLeader };
static getConstructor(type: string) { static getConstructor(type: string) {
if (type === "GroundUnit") return GroundUnit; if (type === "GroundUnit") return GroundUnit;
@@ -156,7 +156,7 @@ export class Unit extends CustomMarker {
this.on('contextmenu', (e) => this.#onContextMenu(e)); this.on('contextmenu', (e) => this.#onContextMenu(e));
this.on('mouseover', () => { if (this.belongsToCommandedCoalition()) this.setHighlighted(true); }) this.on('mouseover', () => { if (this.belongsToCommandedCoalition()) this.setHighlighted(true); })
this.on('mouseout', () => { this.setHighlighted(false); }) this.on('mouseout', () => { this.setHighlighted(false); })
getMap().on("zoomend", () => {this.#onZoom();}) getMap().on("zoomend", () => { this.#onZoom(); })
/* Deselect units if they are hidden */ /* Deselect units if they are hidden */
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => { document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
@@ -222,7 +222,7 @@ export class Unit extends CustomMarker {
case DataIndexes.radio: this.#radio = dataExtractor.extractRadio(); break; case DataIndexes.radio: this.#radio = dataExtractor.extractRadio(); break;
case DataIndexes.generalSettings: this.#generalSettings = dataExtractor.extractGeneralSettings(); break; case DataIndexes.generalSettings: this.#generalSettings = dataExtractor.extractGeneralSettings(); break;
case DataIndexes.ammo: this.#ammo = dataExtractor.extractAmmo(); break; case DataIndexes.ammo: this.#ammo = dataExtractor.extractAmmo(); break;
case DataIndexes.contacts: this.#contacts = dataExtractor.extractContacts(); document.dispatchEvent(new CustomEvent("contactsUpdated", {detail: this})); break; case DataIndexes.contacts: this.#contacts = dataExtractor.extractContacts(); document.dispatchEvent(new CustomEvent("contactsUpdated", { detail: this })); break;
case DataIndexes.activePath: this.#activePath = dataExtractor.extractActivePath(); break; case DataIndexes.activePath: this.#activePath = dataExtractor.extractActivePath(); break;
case DataIndexes.isLeader: this.#isLeader = dataExtractor.extractBool(); break; case DataIndexes.isLeader: this.#isLeader = dataExtractor.extractBool(); break;
} }
@@ -314,7 +314,7 @@ export class Unit extends CustomMarker {
getLiveryID(): string { getLiveryID(): string {
const liveryID = this.getDatabase()?.getByName(this.getName())?.liveryID; const liveryID = this.getDatabase()?.getByName(this.getName())?.liveryID;
return liveryID? liveryID: ""; return liveryID ? liveryID : "";
} }
setAlive(newAlive: boolean) { setAlive(newAlive: boolean) {
@@ -438,7 +438,15 @@ export class Unit extends CustomMarker {
var unitIcon = document.createElement("div"); var unitIcon = document.createElement("div");
unitIcon.classList.add("unit-icon"); unitIcon.classList.add("unit-icon");
var img = document.createElement("img"); var img = document.createElement("img");
img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`; var imgSrc;
/* If a unit does not belong to the commanded coalition or it is not visually detected, show it with the generic aircraft square */
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)))
imgSrc = this.getMarkerCategory();
else
imgSrc = "aircraft";
img.src = `/resources/theme/images/units/${imgSrc}.svg`;
img.onload = () => SVGInjector(img); img.onload = () => SVGInjector(img);
unitIcon.appendChild(img); unitIcon.appendChild(img);
unitIcon.toggleAttribute("data-rotate-to-heading", iconOptions.rotateToHeading); unitIcon.toggleAttribute("data-rotate-to-heading", iconOptions.rotateToHeading);
@@ -503,12 +511,12 @@ export class Unit extends CustomMarker {
updateVisibility() { updateVisibility() {
const hiddenUnits = getUnitsManager().getHiddenTypes(); const hiddenUnits = getUnitsManager().getHiddenTypes();
var hidden = ((this.#human && hiddenUnits.includes("human")) || var hidden = ((this.#human && hiddenUnits.includes("human")) ||
(this.#controlled == false && hiddenUnits.includes("dcs")) || (this.#controlled == false && hiddenUnits.includes("dcs")) ||
(hiddenUnits.includes(this.getMarkerCategory())) || (hiddenUnits.includes(this.getMarkerCategory())) ||
(hiddenUnits.includes(this.#coalition)) || (hiddenUnits.includes(this.#coalition)) ||
(!this.belongsToCommandedCoalition() && (this.#detectionMethods.length == 0 || (this.#detectionMethods.length == 1 && this.#detectionMethods[0] === RWR))) || (!this.belongsToCommandedCoalition() && (this.#detectionMethods.length == 0 || (this.#detectionMethods.length == 1 && this.#detectionMethods[0] === RWR))) ||
(getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getMap().getZoom() < 13 && (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) && (getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getMap().getZoom() < 13 && (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) &&
!(this.getSelected()); !(this.getSelected());
this.setHidden(hidden || !this.#alive); this.setHidden(hidden || !this.#alive);
} }
@@ -519,7 +527,7 @@ export class Unit extends CustomMarker {
/* Add the marker if not present */ /* Add the marker if not present */
if (!getMap().hasLayer(this) && !this.getHidden()) { if (!getMap().hasLayer(this) && !this.getHidden()) {
if (getMap().isZooming()) if (getMap().isZooming())
this.once("zoomend", () => {this.addTo(getMap())}) this.once("zoomend", () => { this.addTo(getMap()) })
else else
this.addTo(getMap()); this.addTo(getMap());
} }
@@ -567,6 +575,18 @@ export class Unit extends CustomMarker {
return false; return false;
} }
isInViewport() {
const mapBounds = getMap().getBounds();
const unitPos = this.getPosition();
return (unitPos.lng > mapBounds.getWest()
&& unitPos.lng < mapBounds.getEast()
&& unitPos.lat > mapBounds.getSouth()
&& unitPos.lat < mapBounds.getNorth());
}
/********************** Unit commands *************************/ /********************** Unit commands *************************/
addDestination(latlng: L.LatLng) { addDestination(latlng: L.LatLng) {
if (!this.#human) { if (!this.#human) {
@@ -711,21 +731,25 @@ export class Unit extends CustomMarker {
if (!e.originalEvent.ctrlKey) if (!e.originalEvent.ctrlKey)
getUnitsManager().deselectAllUnits(); getUnitsManager().deselectAllUnits();
this.setSelected( !this.getSelected() ); this.setSelected(!this.getSelected());
if ( this.getSelected() ) { const detail = { "detail": { "unit": this } };
document.dispatchEvent( new CustomEvent( "unitSelection", { "detail": this })); if (this.getSelected())
} else { document.dispatchEvent(new CustomEvent("unitSelected", detail));
document.dispatchEvent( new CustomEvent( "unitDeselection", { "detail": this })); else
} document.dispatchEvent(new CustomEvent("unitDeselection", { "detail": this }));
} }
} }
this.#timer = window.setTimeout(() => { this.#timer = window.setTimeout(() => { this.#preventClick = false; }, 200);
this.#preventClick = false;
}, 200);
} }
#onDoubleClick(e: any) { #onDoubleClick(e: any) {
const unitsManager = getUnitsManager();
Object.values(unitsManager.getUnits()).forEach((unit: Unit) => {
if (unit.getAlive() === true && unit.getName() === this.getName() && unit.isInViewport())
unitsManager.selectUnit(unit.ID, false);
});
clearTimeout(this.#timer); clearTimeout(this.#timer);
this.#preventClick = true; this.#preventClick = true;
} }
@@ -1050,16 +1074,17 @@ export class Unit extends CustomMarker {
export class AirUnit extends Unit { export class AirUnit extends Unit {
getIconOptions() { getIconOptions() {
var belongsToCommandedCoalition = this.belongsToCommandedCoalition();
return { return {
showState: this.belongsToCommandedCoalition(), showState: belongsToCommandedCoalition,
showVvi: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), showVvi: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showHotgroup: this.belongsToCommandedCoalition(), showHotgroup: belongsToCommandedCoalition,
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), showUnitIcon: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showShortLabel: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value))), showShortLabel: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value))),
showFuel: this.belongsToCommandedCoalition(), showFuel: belongsToCommandedCoalition,
showAmmo: this.belongsToCommandedCoalition(), showAmmo: belongsToCommandedCoalition,
showSummary: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), showSummary: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showCallsign: this.belongsToCommandedCoalition(), showCallsign: belongsToCommandedCoalition,
rotateToHeading: false rotateToHeading: false
}; };
} }
@@ -1091,16 +1116,17 @@ export class GroundUnit extends Unit {
} }
getIconOptions() { getIconOptions() {
var belongsToCommandedCoalition = this.belongsToCommandedCoalition();
return { return {
showState: this.belongsToCommandedCoalition(), showState: belongsToCommandedCoalition,
showVvi: false, showVvi: false,
showHotgroup: this.belongsToCommandedCoalition(), showHotgroup: belongsToCommandedCoalition,
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), showUnitIcon: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showShortLabel: false, showShortLabel: false,
showFuel: false, showFuel: false,
showAmmo: false, showAmmo: false,
showSummary: false, showSummary: false,
showCallsign: this.belongsToCommandedCoalition(), showCallsign: belongsToCommandedCoalition,
rotateToHeading: false rotateToHeading: false
}; };
} }
@@ -1111,7 +1137,7 @@ export class GroundUnit extends Unit {
getType() { getType() {
var blueprint = groundUnitDatabase.getByName(this.getName()); var blueprint = groundUnitDatabase.getByName(this.getName());
return blueprint?.type? blueprint.type: ""; return blueprint?.type ? blueprint.type : "";
} }
} }
@@ -1121,16 +1147,17 @@ export class NavyUnit extends Unit {
} }
getIconOptions() { getIconOptions() {
var belongsToCommandedCoalition = this.belongsToCommandedCoalition();
return { return {
showState: this.belongsToCommandedCoalition(), showState: belongsToCommandedCoalition,
showVvi: false, showVvi: false,
showHotgroup: true, showHotgroup: true,
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), showUnitIcon: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showShortLabel: false, showShortLabel: false,
showFuel: false, showFuel: false,
showAmmo: false, showAmmo: false,
showSummary: false, showSummary: false,
showCallsign: this.belongsToCommandedCoalition(), showCallsign: belongsToCommandedCoalition,
rotateToHeading: false rotateToHeading: false
}; };
} }
@@ -1145,6 +1172,6 @@ export class NavyUnit extends Unit {
getType() { getType() {
var blueprint = navyUnitDatabase.getByName(this.getName()); var blueprint = navyUnitDatabase.getByName(this.getName());
return blueprint?.type? blueprint.type: ""; return blueprint?.type ? blueprint.type : "";
} }
} }