228 lines
7.2 KiB
TypeScript

import { LatLng, LatLngExpression, Map, Point, Polygon, PolylineOptions, DivIcon, Marker } from "leaflet";
import { getApp } from "../../olympusapp";
import { DraggableHandle } from "./coalitionareahandle";
import { CoalitionAreaMiddleHandle } from "./coalitionareamiddlehandle";
import { BLUE_COMMANDER, colors, RED_COMMANDER } from "../../constants/constants";
import { Coalition } from "../../types/types";
import { polyCenter } from "../../other/utils";
import { CoalitionAreaChangedEvent, CoalitionAreaSelectedEvent } from "../../events";
let totalPolygons = 0;
export class CoalitionPolygon extends Polygon {
#coalition: Coalition = "blue";
#selected: boolean = true;
#creating: boolean = false;
#handles: DraggableHandle[] = [];
#middleHandles: CoalitionAreaMiddleHandle[] = [];
#activeIndex: number = 0;
#labelText: string;
#label: Marker;
#updateTimeout: number | null = null;
constructor(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][], options?: PolylineOptions, creating = true) {
if (options === undefined) options = {};
totalPolygons++;
options.bubblingMouseEvents = false;
options.interactive = false;
//@ts-ignore draggable option added by leaflet-path-drag
options.draggable = true;
super(latlngs, options);
this.#setColors();
this.#labelText = `Polygon ${totalPolygons}`;
this.#creating = creating;
if ([BLUE_COMMANDER, RED_COMMANDER].includes(getApp().getMissionManager().getCommandModeOptions().commandMode))
this.setCoalition(getApp().getMissionManager().getCommandedCoalition());
this.on("drag", () => {
this.#setHandles();
this.#setMiddleHandles();
this.#drawLabel();
if (this.#updateTimeout) window.clearTimeout(this.#updateTimeout);
this.#updateTimeout = window.setTimeout(() => {
CoalitionAreaChangedEvent.dispatch(this);
this.#updateTimeout = null;
}, 500);
});
getApp().getMap().addLayer(this);
}
setCoalition(coalition: Coalition) {
this.#coalition = coalition;
this.#setColors();
CoalitionAreaChangedEvent.dispatch(this);
}
getCoalition() {
return this.#coalition;
}
setSelected(selected: boolean) {
this.#selected = selected;
this.#setColors();
this.#setHandles();
this.#drawLabel();
this.setOpacity(selected ? 1 : 0.5);
if (!this.getSelected() && this.getCreating()) {
/* Remove the vertex we were working on */
var latlngs = this.getLatLngs()[0] as LatLng[];
latlngs.splice(this.#activeIndex, 1);
this.setLatLngs(latlngs);
this.setCreating(false);
}
if (selected) CoalitionAreaSelectedEvent.dispatch(this);
//@ts-ignore draggable option added by leaflet-path-drag
selected ? this.dragging.enable() : this.dragging.disable();
}
getSelected() {
return this.#selected;
}
setCreating(creating: boolean) {
this.#creating = creating;
this.#setHandles();
var latlngs = this.getLatLngs()[0] as LatLng[];
/* Remove areas with less than 2 vertexes */
if (latlngs.length <= 2) getApp().getCoalitionAreasManager().deleteCoalitionArea(this);
}
getCreating() {
return this.#creating;
}
addTemporaryLatLng(latlng: LatLng) {
this.#activeIndex++;
var latlngs = this.getLatLngs()[0] as LatLng[];
latlngs.splice(this.#activeIndex, 0, latlng);
this.setLatLngs(latlngs);
this.#setHandles();
}
setOpacity(opacity: number) {
this.setStyle({ opacity: opacity, fillOpacity: opacity * 0.25 });
}
getLabelText() {
return this.#labelText;
}
setLabelText(labelText: string) {
this.#labelText = labelText;
this.#drawLabel();
CoalitionAreaChangedEvent.dispatch(this);
}
onAdd(map: Map): this {
super.onAdd(map);
this.#drawLabel();
return this;
}
onRemove(map: Map): this {
super.onRemove(map);
this.#label?.removeFrom(map);
this.#handles.concat(this.#middleHandles).forEach((handle: DraggableHandle | CoalitionAreaMiddleHandle) => handle.removeFrom(map));
return this;
}
setLatLngs(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]) {
super.setLatLngs(latlngs);
this.#drawLabel();
if (this.#updateTimeout) window.clearTimeout(this.#updateTimeout);
this.#updateTimeout = window.setTimeout(() => {
CoalitionAreaChangedEvent.dispatch(this);
this.#updateTimeout = null;
}, 500);
return this;
}
#setColors() {
let coalitionColor = colors.NEUTRAL_COALITION;
if (this.getCoalition() === "blue") coalitionColor = colors.BLUE_COALITION;
else if (this.getCoalition() === "red") coalitionColor = colors.RED_COALITION;
this.setStyle({
color: this.getSelected() ? "white" : coalitionColor,
fillColor: coalitionColor,
});
}
#setHandles() {
this.#handles.forEach((handle: DraggableHandle) => handle.removeFrom(getApp().getMap()));
this.#handles = [];
if (this.getSelected()) {
var latlngs = this.getLatLngs()[0] as LatLng[];
latlngs.forEach((latlng: LatLng, idx: number) => {
/* Add the polygon vertex handle (for moving the vertex) */
const handle = new DraggableHandle(latlng);
handle.addTo(getApp().getMap());
handle.on("drag", (e: any) => {
var latlngs = this.getLatLngs()[0] as LatLng[];
latlngs[idx] = e.target.getLatLng();
this.setLatLngs(latlngs);
this.#setMiddleHandles();
});
this.#handles.push(handle);
});
}
this.#setMiddleHandles();
}
#setMiddleHandles() {
this.#middleHandles.forEach((handle: CoalitionAreaMiddleHandle) => handle.removeFrom(getApp().getMap()));
this.#middleHandles = [];
var latlngs = this.getLatLngs()[0] as LatLng[];
if (this.getSelected() && latlngs.length >= 2) {
var lastLatLng: LatLng | null = null;
latlngs.concat([latlngs[0]]).forEach((latlng: LatLng, idx: number) => {
/* Add the polygon middle point handle (for adding new vertexes) */
if (lastLatLng != null) {
const handle1Point = getApp().getMap().latLngToLayerPoint(latlng);
const handle2Point = getApp().getMap().latLngToLayerPoint(lastLatLng);
const middlePoint = new Point((handle1Point.x + handle2Point.x) / 2, (handle1Point.y + handle2Point.y) / 2);
const middleLatLng = getApp().getMap().layerPointToLatLng(middlePoint);
const middleHandle = new CoalitionAreaMiddleHandle(middleLatLng);
middleHandle.addTo(getApp().getMap());
middleHandle.on("click", (e: any) => {
this.#activeIndex = idx - 1;
this.addTemporaryLatLng(middleLatLng);
});
this.#middleHandles.push(middleHandle);
}
lastLatLng = latlng;
});
}
}
#drawLabel() {
if (this.#label) {
this.#label.removeFrom(this._map);
}
if ((this.getLatLngs()[0] as LatLng[]).length > 2) {
this.#label = new Marker(polyCenter(this), {
icon: new DivIcon({
className: "label",
html: this.#labelText,
iconSize: [100, 40],
}),
interactive: false,
}).addTo(this._map);
this.#label.getElement()?.classList.add(`ol-coalitionarea-label`, `${this.#selected ? "selected" : `${this.#coalition}`}`);
}
}
}