added MEasurement-tool, added Dispatch-name auto change

This commit is contained in:
PxlLoewe
2025-06-08 18:15:47 -07:00
parent b553f8107d
commit 448bd94d44
14 changed files with 202 additions and 84 deletions

View File

@@ -10,6 +10,7 @@ import { AircraftLayer } from "_components/map/AircraftMarker";
import { MarkerCluster } from "_components/map/_components/MarkerCluster";
import { useEffect, useRef } from "react";
import { Map as TMap } from "leaflet";
import { DistanceLayer } from "_components/map/Measurement";
const Map = () => {
const ref = useRef<TMap | null>(null);
@@ -49,6 +50,7 @@ const Map = () => {
<MarkerCluster />
<MissionLayer />
<AircraftLayer />
<DistanceLayer />
</MapContainer>
);
};

View File

@@ -0,0 +1,102 @@
import "leaflet.polylinemeasure";
import "leaflet.polylinemeasure/Leaflet.PolylineMeasure.css";
import { useEffect, useRef } from "react";
import { useMap } from "react-leaflet";
import L from "leaflet";
export const DistanceLayer = () => {
const map = useMap();
const added = useRef(false);
useEffect(() => {
if (added.current) return;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(L.control as any)
.polylineMeasure({
position: "topleft",
unit: "metres", // Show imperial or metric distances. Values: 'metres', 'landmiles', 'nauticalmiles'
clearMeasurementsOnStop: true, // Clear all the measurements when the control is unselected
showBearings: true, // Whether bearings are displayed within the tooltips
bearingTextIn: "In", // language dependend label for inbound bearings
bearingTextOut: "Out", // language dependend label for outbound bearings
tooltipTextFinish: "Klicken zum <b>Beenden</b><br>",
tooltipTextDelete: "SHIFT+Click zum <b>Löschen</b>",
tooltipTextMove: "Klicken und ziehen zum <b>Verschieben</b><br>",
tooltipTextResume: "<br>CTRL+Click zum <b>Forsetzen</b>",
tooltipTextAdd: "CTRL+Click zum <b>Hinzufügen</b>",
// language dependend labels for point's tooltips
measureControlTitleOn: "Messung starten", // Title for the control going to be switched on
measureControlTitleOff: "Messung beenden", // Title for the control going to be switched off
measureControlLabel: "&#128207", // Label of the Measure control (maybe a unicode symbol)
measureControlClasses: ["pointer"], // Classes to apply to the Measure control
showClearControl: true, // Show a control to clear all the measurements
clearControlTitle: "Messung löschen", // Title text to show on the clear measurements control button
clearControlLabel: "&times", // Label of the Clear control (maybe a unicode symbol)
clearControlClasses: ["pointer"], // Classes to apply to clear control button
unitControlClasses: ["pointer"],
showUnitControl: true, // Show a control to change the units of measurements
unitControlTitle: {
// Title texts to show on the Unit Control
text: "Einheit ändern",
kilometres: "Kilometer",
nauticalmiles: "Nautische Meilen",
},
unitControlLabel: {
// Unit symbols to show in the Unit Control and measurement labels
metres: "m",
kilometres: "km",
feet: "ft",
landmiles: "mi",
nauticalmiles: "nm",
},
tempLine: {
// Styling settings for the temporary dashed line
color: "#00f", // Dashed line color
weight: 2, // Dashed line weight
},
fixedLine: {
// Styling for the solid line
color: "#006", // Solid line color
weight: 2, // Solid line weight
},
arrow: {
// Styling of the midway arrow
color: "#000", // Color of the arrow
},
startCircle: {
// Style settings for circle marker indicating the starting point of the polyline
color: "#000000", // Color of the border of the circle
weight: 1, // Weight of the circle
fillColor: "#000000", // Fill color of the circle
fillOpacity: 1, // Fill opacity of the circle
radius: 3, // Radius of the circle
},
intermedCircle: {
// Style settings for all circle markers between startCircle and endCircle
color: "#000", // Color of the border of the circle
weight: 1, // Weight of the circle
fillColor: "#000000", // Fill color of the circle
fillOpacity: 1, // Fill opacity of the circle
radius: 3, // Radius of the circle
},
currentCircle: {
// Style settings for circle marker indicating the latest point of the polyline during drawing a line
color: "#000000", // Color of the border of the circle
weight: 1, // Weight of the circle
fillColor: "#FFFFFF", // Fill color of the circle
fillOpacity: 1, // Fill opacity of the circle
radius: 3, // Radius of the circle
},
endCircle: {
// Style settings for circle marker indicating the last point of the polyline
color: "#000", // Color of the border of the circle
weight: 1, // Weight of the circle
fillColor: "#ffffff", // Fill color of the circle
fillOpacity: 1, // Fill opacity of the circle
radius: 3, // Radius of the circle
},
})
.addTo(map);
added.current = true;
}, [map]);
return null;
};

View File

@@ -18,6 +18,7 @@ import {
SmartphoneNfc,
CheckCheck,
Cross,
Radio,
} from "lucide-react";
import {
getPublicUser,
@@ -41,6 +42,7 @@ import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
import { HPGValidationRequired } from "_helpers/hpgValidationRequired";
import { getOsmAddress } from "_querys/osm";
import { hpgStateToFMSStatus } from "_helpers/hpgStateToFmsStatus";
import { cn } from "_helpers/cn";
const Einsatzdetails = ({
mission,
@@ -428,7 +430,7 @@ const Rettungsmittel = ({ mission }: { mission: Mission }) => {
? [{ label: "Rettungsdienst", value: "RTW", type: "vehicle" as const }]
: []),
...(!mission.hpgPoliceState || mission.hpgPoliceState === "NOT_REQUESTED"
? [{ label: "POLizei", value: "POL", type: "vehicle" as const }]
? [{ label: "Polizei", value: "POL", type: "vehicle" as const }]
: []),
].sort((a, b) => {
// 1. Vehicles first
@@ -443,7 +445,6 @@ const Rettungsmittel = ({ mission }: { mission: Mission }) => {
// 3. Otherwise, sort alphabetically by label
return a.label.localeCompare(b.label);
return 0;
});
useEffect(() => {
@@ -558,25 +559,17 @@ const Rettungsmittel = ({ mission }: { mission: Mission }) => {
}}
value={typeof selectedStation === "string" ? selectedStation : selectedStation?.id}
>
{allStations
?.filter((s) => !mission.missionStationIds.includes(s.id))
?.map((station) => (
<option
key={station.id}
value={station.id}
onClick={() => {
setSelectedStation(station);
}}
>
{station.bosCallsign}
</option>
))}
<option disabled value={"default"}>
Fahrzeuge:
</option>
{stationsOptions.map((option) => (
<option key={option.value} value={option.value}>
<option
key={option.value}
value={option.value}
className={cn(
"flex gap-2",
"isOnline" in option && option?.isOnline && "text-green-500",
)}
>
{option.label}
{"isOnline" in option && option?.isOnline && " (Online)"}
</option>
))}
</select>