diff --git a/client/copy.bat b/client/copy.bat index f163f70e..cacd14c4 100644 --- a/client/copy.bat +++ b/client/copy.bat @@ -1,2 +1,3 @@ copy .\\node_modules\\leaflet\\dist\\leaflet.css .\\public\\stylesheets\\leaflet\\leaflet.css copy .\\node_modules\\leaflet.nauticscale\\dist\\leaflet.nauticscale.js .\\public\\javascripts\\leaflet.nauticscale.js +copy .\\node_modules\\leaflet-path-drag\\dist\\L.Path.Drag.js .\\public\\javascripts\\L.Path.Drag.js \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index 2fc981a0..4907e9c1 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -19,6 +19,7 @@ "formatcoords": "^1.1.3", "leaflet": "^1.9.3", "leaflet-control-mini-map": "^0.4.0", + "leaflet-path-drag": "*", "leaflet.nauticscale": "^1.1.0", "morgan": "~1.9.1", "save": "^2.9.0" @@ -4060,6 +4061,11 @@ "leaflet": ">=1.7.0" } }, + "node_modules/leaflet-path-drag": { + "version": "1.8.0-beta.3", + "resolved": "https://registry.npmjs.org/leaflet-path-drag/-/leaflet-path-drag-1.8.0-beta.3.tgz", + "integrity": "sha512-kpZ6sPOKlR+m+VChIzZZ7XFH4C+VGTrAxgnM4UN5iYl7lJ00iDOxS+r717bDf/xFFHB6n2jpUp9vvzjjteMpeQ==" + }, "node_modules/leaflet.nauticscale": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/leaflet.nauticscale/-/leaflet.nauticscale-1.1.0.tgz", @@ -8764,6 +8770,11 @@ "integrity": "sha512-qnetYIYFqlrAbX7MaGsAkBsuA2fg3Z4xDRlEXJN1wSrnhNsIhQUzXt7Z3vapdEzx4r7VUqWTaqHYd7eY5C6Gfw==", "requires": {} }, + "leaflet-path-drag": { + "version": "1.8.0-beta.3", + "resolved": "https://registry.npmjs.org/leaflet-path-drag/-/leaflet-path-drag-1.8.0-beta.3.tgz", + "integrity": "sha512-kpZ6sPOKlR+m+VChIzZZ7XFH4C+VGTrAxgnM4UN5iYl7lJ00iDOxS+r717bDf/xFFHB6n2jpUp9vvzjjteMpeQ==" + }, "leaflet.nauticscale": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/leaflet.nauticscale/-/leaflet.nauticscale-1.1.0.tgz", diff --git a/client/package.json b/client/package.json index 5030d648..9385bdc3 100644 --- a/client/package.json +++ b/client/package.json @@ -21,6 +21,7 @@ "formatcoords": "^1.1.3", "leaflet": "^1.9.3", "leaflet-control-mini-map": "^0.4.0", + "leaflet-path-drag": "*", "leaflet.nauticscale": "^1.1.0", "morgan": "~1.9.1", "save": "^2.9.0" diff --git a/client/public/javascripts/L.Path.Drag.js b/client/public/javascripts/L.Path.Drag.js new file mode 100644 index 00000000..b6dec124 --- /dev/null +++ b/client/public/javascripts/L.Path.Drag.js @@ -0,0 +1,6 @@ +/** + * Leaflet vector features drag functionality + * @author Alexander Milevski + * @preserve + */ +L.Path.include({_transform:function(t){if(this._renderer){if(t){this._renderer.transformPath(this,t)}else{this._renderer._resetTransformPath(this);this._update()}}return this},_onMouseClick:function(t){if(this.dragging&&this.dragging.moved()||this._map.dragging&&this._map.dragging.moved()){return}this._fireMouseEvent(t)}});var END={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"};var MOVE={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"};function distance(t,a){var i=t.x-a.x,n=t.y-a.y;return Math.sqrt(i*i+n*n)}L.Handler.PathDrag=L.Handler.extend({statics:{DRAGGING_CLS:"leaflet-path-draggable"},initialize:function(t){this._path=t;this._matrix=null;this._startPoint=null;this._dragStartPoint=null;this._mapDraggingWasEnabled=false;this._path._dragMoved=false},addHooks:function(){this._path.on("mousedown",this._onDragStart,this);this._path.options.className=this._path.options.className?this._path.options.className+" "+L.Handler.PathDrag.DRAGGING_CLS:L.Handler.PathDrag.DRAGGING_CLS;if(this._path._path){L.DomUtil.addClass(this._path._path,L.Handler.PathDrag.DRAGGING_CLS)}},removeHooks:function(){this._path.off("mousedown",this._onDragStart,this);this._path.options.className=this._path.options.className.replace(new RegExp("\\s+"+L.Handler.PathDrag.DRAGGING_CLS),"");if(this._path._path){L.DomUtil.removeClass(this._path._path,L.Handler.PathDrag.DRAGGING_CLS)}},moved:function(){return this._path._dragMoved},_onDragStart:function(t){var a=t.originalEvent._simulated?"touchstart":t.originalEvent.type;this._mapDraggingWasEnabled=false;this._startPoint=t.containerPoint.clone();this._dragStartPoint=t.containerPoint.clone();this._matrix=[1,0,0,1,0,0];L.DomEvent.stop(t.originalEvent);L.DomUtil.addClass(this._path._renderer._container,"leaflet-interactive");L.DomEvent.on(document,MOVE[a],this._onDrag,this).on(document,END[a],this._onDragEnd,this);if(this._path._map.dragging.enabled()){this._path._map.dragging.disable();this._mapDraggingWasEnabled=true}this._path._dragMoved=false;if(this._path._popup){this._path._popup.close()}this._replaceCoordGetters(t)},_onDrag:function(t){L.DomEvent.stop(t);var a=t.touches&&t.touches.length>=1?t.touches[0]:t;var i=this._path._map.mouseEventToContainerPoint(a);if(t.type==="touchmove"&&!this._path._dragMoved){var n=this._dragStartPoint.distanceTo(i);if(n<=this._path._map.options.tapTolerance){return}}var e=i.x;var r=i.y;var s=e-this._startPoint.x;var o=r-this._startPoint.y;if(s||o){if(!this._path._dragMoved){this._path._dragMoved=true;this._path.options.interactive=false;this._path._map.dragging._draggable._moved=true;this._path.fire("dragstart",t);this._path.bringToFront()}this._matrix[4]+=s;this._matrix[5]+=o;this._startPoint.x=e;this._startPoint.y=r;this._path.fire("predrag",t);this._path._transform(this._matrix);this._path.fire("drag",t)}},_onDragEnd:function(t){var a=this._path._map.mouseEventToContainerPoint(t);var i=this.moved();if(i){this._transformPoints(this._matrix);this._path._updatePath();this._path._project();this._path._transform(null);L.DomEvent.stop(t)}L.DomEvent.off(document,"mousemove touchmove",this._onDrag,this);L.DomEvent.off(document,"mouseup touchend",this._onDragEnd,this);this._restoreCoordGetters();if(i){this._path.fire("dragend",{distance:distance(this._dragStartPoint,a)});var n=this._path._containsPoint;this._path._containsPoint=L.Util.falseFn;L.Util.requestAnimFrame(function(){this._path._dragMoved=false;this._path.options.interactive=true;this._path._containsPoint=n},this)}if(this._mapDraggingWasEnabled){this._path._map.dragging.enable()}},_transformPoints:function(t,a){var i=this._path;var n,e,r;var s=L.point(t[4],t[5]);var o=i._map.options.crs;var h=o.transformation;var _=o.scale(i._map.getZoom());var g=o.projection;var d=h.untransform(s,_).subtract(h.untransform(L.point(0,0),_));var p=!a;i._bounds=new L.LatLngBounds;if(i._point){a=g.unproject(g.project(i._latlng)._add(d));if(p){i._latlng=a;i._point._add(s)}}else if(i._rings||i._parts){var l=i._rings||i._parts;var f=i._latlngs;a=a||f;if(!L.Util.isArray(f[0])){f=[f];a=[a]}for(n=0,e=l.length;n :last-child { .ol-panel .ol-group-button-toggle { align-items: center; - column-gap: 15px; display: flex; flex-wrap: nowrap; white-space: nowrap; @@ -421,7 +420,7 @@ nav.ol-panel> :last-child { border: 0; display: flex; justify-items: left; - text-indent: 5px; + text-indent: 2px; } .ol-panel .ol-group-button-toggle button::before { @@ -1134,4 +1133,87 @@ input[type=number]::-webkit-outer-spin-button { .ol-switch[data-value="undefined"]>.ol-switch-fill::after { transform: translateX(calc((var(--width) - var(--height)) * 0.5)); +} + +.ol-contexmenu-panel { + padding: 20px; +} + +.ol-coalition-switch[data-value="false"]>.ol-switch-fill { + background-color: var(--primary-blue); +} + +.ol-coalition-switch[data-value="true"]>.ol-switch-fill { + background-color: var(--primary-red); +} + +.ol-coalition-switch[data-value="undefined"]>.ol-switch-fill { + background-color: var(--primary-neutral); +} + +.ol-context-menu>div:nth-child(2) { + align-items: center; + display: flex; + flex-direction: row; + justify-content: space-between; + padding-right: 0px; +} + +.ol-context-menu>ul { + max-height: 200px; + overflow-x: hidden; + overflow-y: auto; +} + +.ol-context-menu .ol-panel { + border-radius: var(--border-radius-sm); + width: 100%; +} + +.ol-context-menu ul { + margin: 0px; +} + +.ol-context-menu>div:nth-child(n+3) { + align-items: center; + display: flex; + flex-direction: column; + justify-content: space-between; + row-gap: 5px; +} + +.ol-context-menu .ol-select-container { + align-self: stretch; + flex: 0 0 auto; + width: 100%; +} + + +.ol-contexmenu-button { + border: none; + border-radius: 0px; + height: 48px; + margin-bottom: -10px; + margin-top: -10px; + width: 48px; +} + +.ol-contexmenu-button:last-of-type { + border-bottom-right-radius: var(--border-radius-sm); + border-top-right-radius: var(--border-radius-sm); +} + +[data-active-coalition="blue"].ol-contexmenu-button:hover, +[data-active-coalition="blue"].ol-contexmenu-button.is-open { + background-color: var(--primary-blue) +} + +[data-active-coalition="red"].ol-contexmenu-button:hover, +[data-active-coalition="red"].ol-contexmenu-button.is-open { + background-color: var(--primary-red) +} + +[data-active-coalition="neutral"].ol-contexmenu-button:hover, +[data-active-coalition="neutral"].ol-contexmenu-button.is-open { + background-color: var(--primary-neutral) } \ No newline at end of file diff --git a/client/public/stylesheets/other/contextmenus.css b/client/public/stylesheets/other/contextmenus.css index 9f50a4d4..f6ecc8a4 100644 --- a/client/public/stylesheets/other/contextmenus.css +++ b/client/public/stylesheets/other/contextmenus.css @@ -35,61 +35,13 @@ width: 50px; } -#coalition-switch[data-value="false"]>.ol-switch-fill { - background-color: var(--primary-blue); -} - -#coalition-switch[data-value="true"]>.ol-switch-fill { - background-color: var(--primary-red); -} - -#coalition-switch[data-value="undefined"]>.ol-switch-fill { - background-color: var(--primary-neutral); -} - -#map-contextmenu>div:nth-child(2) { - align-items: center; - display: flex; - flex-direction: row; - justify-content: space-between; - padding-right: 0px; -} - -#map-contextmenu>ul { - max-height: 200px; - overflow-x: hidden; - overflow-y: auto; -} - -#map-contextmenu .ol-panel { - border-radius: var(--border-radius-sm); - width: 100%; -} - -#map-contextmenu ul { - margin: 0px; -} - -#map-contextmenu>div:nth-child(n+3) { - align-items: center; - display: flex; - flex-direction: column; - justify-content: space-between; - row-gap: 5px; -} - -#map-contextmenu .ol-select-container { - align-self: stretch; - flex: 0 0 auto; - width: 100%; -} - #aircraft-spawn-menu .ol-select.is-open .ol-select-options { max-height: 300px; } #aircraft-spawn-menu>button, -#ground-unit-spawn-menu>button { +#ground-unit-spawn-menu>button, +#iads-menu>button { text-align: center; width: 100%; } @@ -99,7 +51,7 @@ background-size: 48px; } -#ground-unit-spawn-button { +#ground-ol-contexmenu-button { background-image: url("/resources/theme/images/buttons/spawn/ground.svg"); background-size: 48px; } @@ -114,41 +66,24 @@ background-size: 48px; } -.unit-spawn-button { - border: none; - border-radius: 0px; - height: 48px; - margin-bottom: -10px; - margin-top: -10px; - width: 48px; -} - -.unit-spawn-button:last-of-type { - border-bottom-right-radius: var(--border-radius-sm); - border-top-right-radius: var(--border-radius-sm); -} - -[data-active-coalition="blue"].unit-spawn-button:hover, -[data-active-coalition="blue"].unit-spawn-button.is-open, [data-active-coalition="blue"]#active-coalition-label, [data-active-coalition="blue"].deploy-unit-button, -[data-active-coalition="blue"]#spawn-airbase-aircraft-button { +[data-active-coalition="blue"]#spawn-airbase-aircraft-button, +[data-active-coalition="blue"].create-iads-button { background-color: var(--primary-blue) } -[data-active-coalition="red"].unit-spawn-button:hover, -[data-active-coalition="red"].unit-spawn-button.is-open, [data-active-coalition="red"]#active-coalition-label, [data-active-coalition="red"].deploy-unit-button, -[data-active-coalition="red"]#spawn-airbase-aircraft-button { +[data-active-coalition="red"]#spawn-airbase-aircraft-button, +[data-active-coalition="red"].create-iads-button { background-color: var(--primary-red) } -[data-active-coalition="neutral"].unit-spawn-button:hover, -[data-active-coalition="neutral"].unit-spawn-button.is-open, [data-active-coalition="neutral"]#active-coalition-label, [data-active-coalition="neutral"].deploy-unit-button, -[data-active-coalition="neutral"]#spawn-airbase-aircraft-button { +[data-active-coalition="neutral"]#spawn-airbase-aircraft-button, +[data-active-coalition="neutral"].create-iads-button { background-color: var(--primary-neutral) } @@ -407,3 +342,50 @@ width: 180px; z-index: 9999; } + +/* Coalition area context menu */ +#coalition-area-contextmenu { + display: flex; + flex-direction: column; + height: fit-content; + position: absolute; + row-gap: 5px; + width: 225px; + z-index: 9999; +} + +#coalition-area-switch { + margin-right: 10px; + height: 25px; + width: 50px; +} + +#iads-button { + background-image: url("/resources/theme/images/buttons/spawn/aircraft.svg"); + background-size: 48px; +} + +#coalition-area-contextmenu .ol-checkbox { + align-self: flex-start; +} + +#iads-menu .ol-select-options>* { + padding-top: 8px; + padding-bottom: 8px; +} + +#iads-menu .ol-select-options>*:first-child { + padding-top: 15px; +} + +#iads-menu .ol-select-options>*:last-child { + padding-bottom: 15px; +} + +#iads-menu .ol-select { + width: 100%; +} + +#iads-menu { + row-gap: 10px; +} diff --git a/client/src/controls/coalitionareacontextmenu.ts b/client/src/controls/coalitionareacontextmenu.ts new file mode 100644 index 00000000..b4985950 --- /dev/null +++ b/client/src/controls/coalitionareacontextmenu.ts @@ -0,0 +1,71 @@ +import { CoalitionArea } from "../map/coalitionarea"; +import { groundUnitsDatabase } from "../units/groundunitsdatabase"; +import { ContextMenu } from "./contextmenu"; +import { Dropdown } from "./dropdown"; +import { Slider } from "./slider"; +import { Switch } from "./switch"; + +const unitRole = ["AAA", "MANPADS", "Short range SAM", "Long range SAM", "Radar"]; + +export class CoalitionAreaContextMenu extends ContextMenu { + #coalitionSwitch: Switch; + #coalitionArea: CoalitionArea|null = null; + #iadsDensitySlider: Slider; + #iadsRoleDropdown: Dropdown; + //#iadsPeriodDropdown: Dropdown; + + constructor(id: string) { + super(id); + + this.#coalitionSwitch = new Switch("coalition-area-switch", (value: boolean) => this.#onSwitchClick(value)); + this.#coalitionSwitch.setValue(false); + this.#iadsRoleDropdown = new Dropdown("iads-units-role-options", () => {}); + //this.#iadsPeriodDropdown = new Dropdown("iads-period-options", () => {}); + this.#iadsDensitySlider = new Slider("iads-density-slider", 5, 100, "%", (value: number) => {}); + this.#iadsDensitySlider.setIncrement(5); + this.#iadsDensitySlider.setValue(50); + this.#iadsDensitySlider.setActive(true); + + document.addEventListener("coalitionAreaContextMenuShow", (e: any) => { + this.showSubMenu(e.detail.type); + }); + + /* Create the checkboxes to select the unit roles */ + this.#iadsRoleDropdown.setOptionsElements(unitRole.map((unitRole: string) => { + var div = document.createElement("div"); + div.classList.add("ol-checkbox"); + var label = document.createElement("label"); + label.title = `Add ${unitRole}s to the IADS`; + var input = document.createElement("input"); + input.type = "checkbox"; + var span = document.createElement("span"); + span.innerText = unitRole; + label.appendChild(input); + label.appendChild(span); + div.appendChild(label); + return div as HTMLElement; + })); + + + + this.hide(); + } + + showSubMenu(type: string) { + this.getContainer()?.querySelector("#iads-menu")?.classList.toggle("hide", type !== "iads"); + this.getContainer()?.querySelector("#iads-button")?.classList.toggle("is-open", type === "iads"); + this.clip(); + } + + getCoalitionArea() { + return this.#coalitionArea; + } + + setCoalitionArea(coalitionArea: CoalitionArea) { + this.#coalitionArea = coalitionArea; + } + + #onSwitchClick(value: boolean) { + this.getCoalitionArea()?.setCoalition(value? "red": "blue"); + } +} \ No newline at end of file diff --git a/client/src/controls/dropdown.ts b/client/src/controls/dropdown.ts index 2877d80d..66c2a09e 100644 --- a/client/src/controls/dropdown.ts +++ b/client/src/controls/dropdown.ts @@ -50,6 +50,11 @@ export class Dropdown { })); } + setOptionsElements(optionsElements: HTMLElement[]) { + this.#optionsList = []; + this.#options.replaceChildren(...optionsElements); + } + selectText(text: string) { const index = [].slice.call(this.#options.children).findIndex((opt: Element) => opt.querySelector("button")?.innerText === text); if (index > -1) { diff --git a/client/src/controls/mapcontextmenu.ts b/client/src/controls/mapcontextmenu.ts index 51027f01..84f20333 100644 --- a/client/src/controls/mapcontextmenu.ts +++ b/client/src/controls/mapcontextmenu.ts @@ -45,7 +45,7 @@ export class MapContextMenu extends ContextMenu { this.#groundUnitRoleDropdown = new Dropdown("ground-unit-role-options", (role: string) => this.#setGroundUnitRole(role)); this.#groundUnitTypeDropdown = new Dropdown("ground-unit-type-options", (type: string) => this.#setGroundUnitType(type)); - document.addEventListener("contextMenuShow", (e: any) => { + document.addEventListener("mapContextMenuShow", (e: any) => { this.showSubMenu(e.detail.type); }); @@ -92,7 +92,7 @@ export class MapContextMenu extends ContextMenu { this.getContainer()?.querySelector("#aircraft-spawn-menu")?.classList.toggle("hide", type !== "aircraft"); this.getContainer()?.querySelector("#aircraft-spawn-button")?.classList.toggle("is-open", type === "aircraft"); this.getContainer()?.querySelector("#ground-unit-spawn-menu")?.classList.toggle("hide", type !== "ground-unit"); - this.getContainer()?.querySelector("#ground-unit-spawn-button")?.classList.toggle("is-open", type === "ground-unit"); + this.getContainer()?.querySelector("#ground-ol-contexmenu-button")?.classList.toggle("is-open", type === "ground-unit"); this.getContainer()?.querySelector("#smoke-spawn-menu")?.classList.toggle("hide", type !== "smoke"); this.getContainer()?.querySelector("#smoke-spawn-button")?.classList.toggle("is-open", type === "smoke"); this.getContainer()?.querySelector("#explosion-menu")?.classList.toggle("hide", type !== "explosion"); diff --git a/client/src/map/coalitionarea.ts b/client/src/map/coalitionarea.ts new file mode 100644 index 00000000..f3ffee35 --- /dev/null +++ b/client/src/map/coalitionarea.ts @@ -0,0 +1,20 @@ +import { LatLngExpression, Polygon, PolylineOptions } from "leaflet"; +import { getMap } from ".."; + +export class CoalitionArea extends Polygon { + constructor(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][], options?: PolylineOptions) { + if (options === undefined) + options = {}; + + options.bubblingMouseEvents = false; + super(latlngs, options); + + this.on("contextmenu", (e: any) => { + getMap().showCoalitionAreaContextMenu(e, this); + }) + } + + setCoalition(coalition: string) { + this.setStyle({color: coalition, fillColor: coalition}); + } +} \ No newline at end of file diff --git a/client/src/map/map.ts b/client/src/map/map.ts index 04b85d28..d19d5327 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -14,11 +14,14 @@ import { ClickableMiniMap } from "./clickableminimap"; import { SVGInjector } from '@tanem/svg-injector' import { layers as mapLayers, mapBounds, minimapBoundaries } from "../constants/constants"; import { TargetMarker } from "./targetmarker"; +import { CoalitionArea } from "./coalitionarea"; +import { CoalitionAreaContextMenu } from "../controls/coalitionareacontextmenu"; L.Map.addInitHook('addHandler', 'boxSelect', BoxSelect); // TODO would be nice to convert to ts require("../../public/javascripts/leaflet.nauticscale.js") +require("../../public/javascripts/L.Path.Drag.js") /* Map constants */ export const IDLE = "Idle"; @@ -26,6 +29,7 @@ export const MOVE_UNIT = "Move unit"; export const BOMBING = "Bombing"; export const CARPET_BOMBING = "Carpet bombing"; export const FIRE_AT_AREA = "Fire at area"; +export const DRAW_POLYGON = "Draw polygon"; export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "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"]; @@ -51,10 +55,12 @@ export class Map extends L.Map { #destinationGroupRotation: number = 0; #computeDestinationRotation: boolean = false; #destinationRotationCenter: L.LatLng | null = null; - + #polygons: CoalitionArea[] = []; + #mapContextMenu: MapContextMenu = new MapContextMenu("map-contextmenu"); #unitContextMenu: UnitContextMenu = new UnitContextMenu("unit-contextmenu"); #airbaseContextMenu: AirbaseContextMenu = new AirbaseContextMenu("airbase-contextmenu"); + #coalitionAreaContextMenu: CoalitionAreaContextMenu = new CoalitionAreaContextMenu("coalition-area-contextmenu"); #mapSourceDropdown: Dropdown; #optionButtons: { [key: string]: HTMLButtonElement[] } = {} @@ -114,6 +120,12 @@ export class Map extends L.Map { Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); }); + document.addEventListener("toggleMapDraw", (ev: CustomEventInit) => { + if (ev.detail?.type == "polygon") { + this.setState(DRAW_POLYGON); + } + }) + document.addEventListener("unitUpdated", (ev: CustomEvent) => { if (this.#centerUnit != null && ev.detail == this.#centerUnit) this.#panToUnit(this.#centerUnit); @@ -176,6 +188,14 @@ export class Map extends L.Map { this.#createTargetMarker(); this.#hideCursor(); } + else if (this.#state === DRAW_POLYGON) { + this.#resetDestinationMarkers(); + this.#resetTargetMarker(); + this.#showCursor(); + //@ts-ignore draggable option added by plugin + this.#polygons.push(new CoalitionArea([])); + this.#polygons[this.#polygons.length - 1].addTo(this); + } document.dispatchEvent(new CustomEvent("mapStateChanged")); } @@ -188,6 +208,7 @@ export class Map extends L.Map { this.hideMapContextMenu(); this.hideUnitContextMenu(); this.hideAirbaseContextMenu(); + this.hideCoalitionAreaContextMenu(); } showMapContextMenu(e: any) { @@ -238,6 +259,22 @@ export class Map extends L.Map { this.#airbaseContextMenu.hide(); } + showCoalitionAreaContextMenu(e: any, coalitionArea: CoalitionArea) { + this.hideAllContextMenus(); + var x = e.originalEvent.x; + var y = e.originalEvent.y; + this.#coalitionAreaContextMenu.show(x, y, e.latlng); + this.#coalitionAreaContextMenu.setCoalitionArea(coalitionArea); + } + + getCoalitionAreaContextMenu() { + return this.#coalitionAreaContextMenu; + } + + hideCoalitionAreaContextMenu() { + this.#coalitionAreaContextMenu.hide(); + } + /* Mouse coordinates */ getMousePosition() { return this.#lastMousePosition; @@ -363,6 +400,9 @@ export class Map extends L.Map { this.hideAllContextMenus(); if (this.#state === IDLE) { + } + else if (this.#state === DRAW_POLYGON) { + this.#polygons[this.#polygons.length - 1].addLatLng(e.latlng); } else { this.setState(IDLE); @@ -403,6 +443,9 @@ export class Map extends L.Map { getUnitsManager().getSelectedUnits().length > 0? this.setState(MOVE_UNIT): this.setState(IDLE); getUnitsManager().selectedUnitsFireAtArea(this.getMouseCoordinates()); } + else { + this.setState(IDLE); + } } #executeAction(e: any, action: string) { diff --git a/client/src/units/groundunitsdatabase.ts b/client/src/units/groundunitsdatabase.ts index b3ed6b62..e5f838a9 100644 --- a/client/src/units/groundunitsdatabase.ts +++ b/client/src/units/groundunitsdatabase.ts @@ -14,7 +14,7 @@ export class GroundUnitsDatabase extends UnitDatabase { "items": [ ], "roles": [ - "Template" + "SAM Site" ], "code": "", "name": "Default" @@ -31,7 +31,7 @@ export class GroundUnitsDatabase extends UnitDatabase { "fuel": 1, "items": [], "roles": [ - "Template" + "SAM Site" ], "code": "", "name": "Default" @@ -48,7 +48,7 @@ export class GroundUnitsDatabase extends UnitDatabase { "fuel": 1, "items": [], "roles": [ - "Template" + "SAM Site" ], "code": "", "name": "Default" @@ -65,7 +65,7 @@ export class GroundUnitsDatabase extends UnitDatabase { "fuel": 1, "items": [], "roles": [ - "Template" + "SAM Site" ], "code": "", "name": "Default" @@ -82,7 +82,7 @@ export class GroundUnitsDatabase extends UnitDatabase { "fuel": 1, "items": [], "roles": [ - "Template" + "SAM Site" ], "code": "", "name": "Default" @@ -99,7 +99,7 @@ export class GroundUnitsDatabase extends UnitDatabase { "fuel": 1, "items": [], "roles": [ - "Template" + "SAM Site" ], "code": "", "name": "Default" @@ -116,7 +116,7 @@ export class GroundUnitsDatabase extends UnitDatabase { "fuel": 1, "items": [], "roles": [ - "Template" + "SAM Site" ], "code": "", "name": "Default" diff --git a/client/views/other/contextmenus.ejs b/client/views/other/contextmenus.ejs index 0940f076..09da39cd 100644 --- a/client/views/other/contextmenus.ejs +++ b/client/views/other/contextmenus.ejs @@ -1,17 +1,17 @@ -
+
-
- - - - +
+ + + +
-
+
Aircraft role
@@ -56,7 +56,7 @@
-
+
Ground unit role
@@ -76,14 +76,14 @@
-
+
-
+
@@ -96,11 +96,9 @@
-

-
- +

Parking available:

@@ -108,5 +106,45 @@ - +
+ +
+
+
+
+ +
+
+
+
Unit types
+
+ +
+
+ +
+
+
Units period
+
+ +
+
+
+ +
+ +
+ +
+
+
IADS density
+
+ +
+ +
\ No newline at end of file diff --git a/client/views/panels/navbar.ejs b/client/views/panels/navbar.ejs index 922fe414..411f4dc1 100644 --- a/client/views/panels/navbar.ejs +++ b/client/views/panels/navbar.ejs @@ -30,32 +30,28 @@
- +
-
+ data-on-click-params='{ "coalition": "blue" }'>BLUEFOR
+ data-on-click-params='{ "coalition": "red" }'>REDFOR
+ data-on-click-params='{ "coalition": "neutral" }'>NEUTRAL
-
-
-
ATC
+
@@ -63,4 +59,10 @@ data-on-click-params='{"selector": "#strip-board-tower"}'>TWR
+ +
+
+ +
+
\ No newline at end of file