Completed creation of areas

This commit is contained in:
Davide Passoni
2024-08-02 13:17:42 +02:00
parent 86e0e6b3a3
commit a3e92580c2
12 changed files with 406 additions and 90 deletions

View File

@@ -4,6 +4,10 @@ import { CustomMarker } from "../markers/custommarker";
export class CoalitionAreaHandle extends CustomMarker {
constructor(latlng: LatLng) {
super(latlng, { interactive: true, draggable: true });
this.on("add", (e) => {
this.getElement()?.addEventListener("touchstart", (e) => e.stopPropagation());
})
}
createIcon() {

View File

@@ -49,6 +49,10 @@ export class CoalitionCircle extends Circle {
this.#setRadiusHandle();
this.#drawLabel();
});
this.on("remove", () => {
this.#label.removeFrom(this._map);
});
}
setCoalition(coalition: Coalition) {

View File

@@ -6,7 +6,7 @@ import {
Polygon,
PolylineOptions,
DivIcon,
Marker,
Marker
} from "leaflet";
import { getApp } from "../../olympusapp";
import { CoalitionAreaHandle } from "./coalitionareahandle";
@@ -57,6 +57,10 @@ export class CoalitionPolygon extends Polygon {
this.#setMiddleHandles();
this.#drawLabel();
});
this.on("remove", () => {
this.#label.removeFrom(this._map);
});
}
setCoalition(coalition: Coalition) {

View File

@@ -0,0 +1,179 @@
import * as L from "leaflet";
export const initDraggablePath = () => {
//@ts-ignore
L.PathDraggable = L.Draggable.extend({
initialize: function (path) {
this._path = path;
this._canvas = path._map.getRenderer(path) instanceof L.Canvas;
var element = this._canvas
? this._path._map.getRenderer(this._path)._container
: this._path._path;
//@ts-ignore
L.Draggable.prototype.initialize.call(this, element, element, true);
},
_updatePosition: function () {
var e = { originalEvent: this._lastEvent };
this.fire("drag", e);
},
_onDown: function (e) {
var first = e.touches ? e.touches[0] : e;
this._startPoint = new L.Point(first.clientX, first.clientY);
if (
this._canvas &&
!this._path._containsPoint(
this._path._map.mouseEventToLayerPoint(first)
)
) {
return;
}
//@ts-ignore
L.Draggable.prototype._onDown.call(this, e);
e.stopPropagation();
},
});
//@ts-ignore
L.Handler.PathDrag = L.Handler.extend({
initialize: function (path) {
this._path = path;
},
getEvents: function () {
return {
dragstart: this._onDragStart,
drag: this._onDrag,
dragend: this._onDragEnd,
};
},
addHooks: function () {
if (!this._draggable) {
//@ts-ignore
this._draggable = new L.PathDraggable(this._path);
}
this._draggable.on(this.getEvents(), this).enable();
L.DomUtil.addClass(this._draggable._element, "leaflet-path-draggable");
},
removeHooks: function () {
this._draggable.off(this.getEvents(), this).disable();
L.DomUtil.removeClass(this._draggable._element, "leaflet-path-draggable");
},
moved: function () {
return this._draggable && this._draggable._moved;
},
_onDragStart: function () {
this._startPoint = this._draggable._startPoint;
this._path.closePopup().fire("movestart").fire("dragstart");
},
_onDrag: function (e) {
var path = this._path,
event =
e.originalEvent.touches && e.originalEvent.touches.length === 1
? e.originalEvent.touches[0]
: e.originalEvent,
newPoint = L.point(event.clientX, event.clientY),
latlng = path._map.layerPointToLatLng(newPoint);
this._offset = newPoint.subtract(this._startPoint);
this._startPoint = newPoint;
this._path.eachLatLng(this.updateLatLng, this);
path.redraw();
e.latlng = latlng;
e.offset = this._offset;
path.fire("drag", e);
e.latlng = this._path.getCenter
? this._path.getCenter()
: this._path.getLatLng();
path.fire("move", e);
},
_onDragEnd: function (e) {
if (this._path._bounds) this.resetBounds();
this._path.fire("moveend").fire("dragend", e);
},
latLngToLayerPoint: function (latlng) {
// Same as map.latLngToLayerPoint, but without the round().
var projectedPoint = this._path._map.project(L.latLng(latlng));
return projectedPoint._subtract(this._path._map.getPixelOrigin());
},
updateLatLng: function (latlng) {
var oldPoint = this.latLngToLayerPoint(latlng);
oldPoint._add(this._offset);
var newLatLng = this._path._map.layerPointToLatLng(oldPoint);
latlng.lat = newLatLng.lat;
latlng.lng = newLatLng.lng;
},
resetBounds: function () {
//@ts-ignore
this._path._bounds = new L.LatLngBounds();
this._path.eachLatLng(function (latlng) {
this._bounds.extend(latlng);
});
},
});
L.Path.include({
eachLatLng: function (callback, context) {
context = context || this;
var loop = function (latlngs) {
for (var i = 0; i < latlngs.length; i++) {
if (L.Util.isArray(latlngs[i])) loop(latlngs[i]);
else callback.call(context, latlngs[i]);
}
};
loop(this.getLatLngs ? this.getLatLngs() : [this.getLatLng()]);
},
});
L.Path.addInitHook(function () {
//@ts-ignore
this.dragging = new L.Handler.PathDrag(this);
if (this.options.draggable) {
this.once("add", function () {
this.dragging.enable();
});
}
});
};

View File

@@ -3,13 +3,7 @@ import { getApp } from "../olympusapp";
import { BoxSelect } from "./boxselect";
import { Airbase } from "../mission/airbase";
import { Unit } from "../unit/unit";
import {
areaContains,
circleContains,
deg2rad,
getGroundElevation,
polyContains,
} from "../other/utils";
import { areaContains, deg2rad, getFunctionArguments, getGroundElevation } from "../other/utils";
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
import { ClickableMiniMap } from "./clickableminimap";
import {
@@ -38,12 +32,14 @@ import "./markers/stylesheets/units.css";
import "./map.css";
import { CoalitionCircle } from "./coalitionarea/coalitioncircle";
import "leaflet-path-drag";
import { faLeftLong } from "@fortawesome/free-solid-svg-icons";
import { initDraggablePath } from "./coalitionarea/draggablepath";
import { faDrawPolygon, faJetFighter, faMap } from "@fortawesome/free-solid-svg-icons";
/* Register the handler for the box selection */
L.Map.addInitHook("addHandler", "boxSelect", BoxSelect);
initDraggablePath();
export class Map extends L.Map {
/* Options */
#options: MapOptions = MAP_OPTIONS_DEFAULTS;
@@ -413,63 +409,83 @@ export class Map extends L.Map {
return [
{
actions: ["Tap"],
target: faJetFighter,
text: "Select unit",
},
{
actions: ["Shift", "Drag"],
target: faMap,
text: "Box selection",
},
{
actions: ["Press", "Drag"],
target: faMap,
text: "Box selection",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
{
actions: ["Long tap", "Drag"],
text: "Box selection",
},
];
} else if (this.#state === SPAWN_UNIT) {
return [
{
actions: ["Tap"],
target: faMap,
text: "Spawn unit",
},
{
actions: ["Double tap"],
target: faMap,
text: "Exit spawn mode",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
} else if (this.#state === CONTEXT_ACTION) {
return [
{
actions: ["Tap"],
text: this.#contextAction?.getLabel() ?? "",
},
let controls = [
{
actions: ["Double tap"],
text: "Exit action mode",
target: faMap,
text: "Deselect units",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
if (this.#contextAction) {
/* TODO: I don't like this approach, it relies on the arguments names of the callback. We should find a better method */
const args = getFunctionArguments(this.#contextAction.getCallback());
controls.push({
actions: ["Tap"],
target: args.includes("targetUnit")? faJetFighter: faMap,
text: this.#contextAction?.getLabel() ?? "",
});
}
return controls;
} else if (this.#state === COALITIONAREA_EDIT) {
return [
{
actions: ["Tap"],
target: faDrawPolygon,
text: "Select shape",
},
{
actions: ["Double tap"],
target: faMap,
text: "Exit drawing mode",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
@@ -477,14 +493,17 @@ export class Map extends L.Map {
return [
{
actions: ["Tap"],
target: faMap,
text: "Add vertex to polygon",
},
{
actions: ["Double tap"],
target: faMap,
text: "Finalize polygon",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
@@ -492,10 +511,12 @@ export class Map extends L.Map {
return [
{
actions: ["Tap"],
target: faMap,
text: "Add circle",
},
{
actions: ["Drag"],
target: faMap,
text: "Move map location",
},
];
@@ -801,7 +822,8 @@ export class Map extends L.Map {
this.#longPressTimer = window.setTimeout(() => {
/* If the mouse is still being pressed, execute the long press action */
if (this.#isMouseDown) this.#onLongPress(e);
if (this.#isMouseDown && !this.#isDragging && !this.#isZooming)
this.#onLongPress(e);
}, 500);
}
@@ -822,15 +844,20 @@ export class Map extends L.Map {
}
#onShortPress(e: any) {
console.log(`Short press at ${e.latlng}`);
let touchLocation: L.LatLng;
if (e.type === "touchstart")
touchLocation = this.containerPointToLatLng(
this.mouseEventToContainerPoint(e.touches[0])
);
else touchLocation = new L.LatLng(e.latlng.lat, e.latlng.lng);
const location = new L.LatLng(e.latlng.lat, e.latlng.lng);
console.log(`Short press at ${touchLocation}`);
/* Execute the short click action */
if (this.#state === IDLE) {
} else if (this.#state === SPAWN_UNIT) {
if (this.#spawnRequestTable !== null) {
this.#spawnRequestTable.unit.location = location;
this.#spawnRequestTable.unit.location = touchLocation;
getApp()
.getUnitsManager()
.spawnUnits(
@@ -842,7 +869,7 @@ export class Map extends L.Map {
undefined,
(hash) => {
this.addTemporaryMarker(
location,
touchLocation,
this.#spawnRequestTable?.unit.unitType ?? "unknown",
this.#spawnRequestTable?.coalition ?? "blue",
hash
@@ -853,7 +880,7 @@ export class Map extends L.Map {
} else if (this.#state === COALITIONAREA_DRAW_POLYGON) {
const selectedArea = this.getSelectedCoalitionArea();
if (selectedArea && selectedArea instanceof CoalitionPolygon) {
selectedArea.addTemporaryLatLng(location);
selectedArea.addTemporaryLatLng(touchLocation);
}
} else if (this.#state === COALITIONAREA_DRAW_CIRCLE) {
const selectedArea = this.getSelectedCoalitionArea();
@@ -862,13 +889,13 @@ export class Map extends L.Map {
selectedArea.getLatLng().lat == 0 &&
selectedArea.getLatLng().lng == 0
)
selectedArea.setLatLng(location);
selectedArea.setLatLng(touchLocation);
this.setState(COALITIONAREA_EDIT);
}
} else if (this.#state == COALITIONAREA_EDIT) {
this.deselectAllCoalitionAreas();
for (let idx = 0; idx < this.#coalitionAreas.length; idx++) {
if (areaContains(e.latlng, this.#coalitionAreas[idx])) {
if (areaContains(touchLocation, this.#coalitionAreas[idx])) {
this.#coalitionAreas[idx].setSelected(true);
document.dispatchEvent(
new CustomEvent("coalitionAreaSelected", {
@@ -879,18 +906,24 @@ export class Map extends L.Map {
}
}
} else if (this.#state === CONTEXT_ACTION) {
this.executeContextAction(null, e.latlng);
this.executeContextAction(null, touchLocation);
} else {
}
}
#onLongPress(e: any) {
console.log(`Long press at ${e.latlng}`);
let touchLocation: L.LatLng;
if (e.type === "touchstart")
touchLocation = this.containerPointToLatLng(
this.mouseEventToContainerPoint(e.touches[0])
);
else touchLocation = new L.LatLng(e.latlng.lat, e.latlng.lng);
this.deselectAllCoalitionAreas();
console.log(`Long press at ${touchLocation}`);
if (!this.#isDragging && !this.#isZooming) {
if (this.#state == IDLE) {
this.deselectAllCoalitionAreas();
if (this.#state === IDLE) {
if (e.type === "touchstart")
document.dispatchEvent(
new CustomEvent("mapForceBoxSelect", { detail: e })
@@ -908,7 +941,7 @@ export class Map extends L.Map {
this.#lastMousePosition.x = e.originalEvent.x;
this.#lastMousePosition.y = e.originalEvent.y;
this.#lastMouseCoordinates = this.mouseEventToLatLng(e.originalEvent);
this.#lastMouseCoordinates = e.latlng;
}
#onMapMove(e: any) {