{showButtons && (
@@ -339,6 +440,15 @@ export default function MapElement(props: MapElementProps) {
/>
Show personnel
+
+
)}
@@ -354,32 +464,72 @@ export default function MapElement(props: MapElementProps) {
markers={visibleMarkers}
layers={layers}
layerVisibility={layerVisibility}
+ poiLayers={poiLayers}
+ poiLayerVisibility={poiLayerVisibility}
hideLabels={hideLabels}
resolvedMapConfig={resolvedMapConfig}
fitBoundsKey={fitBoundsKey}
/>
)}
- {layers.length > 0 && (
+ {(layers.length > 0 || poiLayers.length > 0) && (
-
Map layers
-
- {layers.map((layer) => (
-
- ))}
-
+ {layers.length > 0 && (
+
+
Map layers
+
+ {layers.map((layer) => (
+
+ ))}
+
+
+ )}
+
+ {poiLayers.length > 0 && (
+
+
POI layers
+
+ {poiLayers.map((poiLayer) => {
+ const layerId = getPoiLayerId(poiLayer);
+
+ return (
+
+ );
+ })}
+
+
+ )}
)}
diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/map/MapboxMapView.tsx b/Web/Resgrid.Web/Areas/User/Apps/src/components/map/MapboxMapView.tsx
index 65996c936..752a023ef 100644
--- a/Web/Resgrid.Web/Areas/User/Apps/src/components/map/MapboxMapView.tsx
+++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/map/MapboxMapView.tsx
@@ -3,6 +3,8 @@ import 'mapbox-gl/dist/mapbox-gl.css';
import {
getLayerColor,
getMarkerIconUrl,
+ getPoiMarkerShapePath,
+ isPoiMarker,
type MapMarkerInfo,
type MapRendererProps,
} from './mapTypes';
@@ -17,6 +19,9 @@ interface MarkerState {
longitude: number;
title: string;
imagePath: string;
+ markerShape: string;
+ color: string;
+ markerType: number;
infoWindowContent: string;
hideLabels: boolean;
}
@@ -26,11 +31,31 @@ function createMarkerElement(markerInfo: MapMarkerInfo, hideLabels: boolean): HT
wrapper.className = 'rg-map__marker';
wrapper.title = hideLabels ? '' : markerInfo.Title;
- const icon = document.createElement('img');
- icon.className = 'rg-map__marker-icon';
- icon.src = getMarkerIconUrl(markerInfo);
- icon.alt = '';
- wrapper.appendChild(icon);
+ if (isPoiMarker(markerInfo)) {
+ wrapper.classList.add('rg-map__marker--poi');
+ wrapper.style.setProperty('--rg-map-poi-color', markerInfo.Color || '#2563eb');
+
+ const markerShape = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ markerShape.setAttribute('viewBox', '-24 -48 48 48');
+ markerShape.setAttribute('class', 'rg-map__poi-marker-shape');
+
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ path.setAttribute('d', getPoiMarkerShapePath(markerInfo.Marker));
+ markerShape.appendChild(path);
+
+ const icon = document.createElement('span');
+ icon.className = `map-icon ${markerInfo.ImagePath || 'map-icon-map-pin'} rg-map__poi-marker-icon`;
+ icon.setAttribute('aria-hidden', 'true');
+
+ wrapper.appendChild(markerShape);
+ wrapper.appendChild(icon);
+ } else {
+ const icon = document.createElement('img');
+ icon.className = 'rg-map__marker-icon';
+ icon.src = getMarkerIconUrl(markerInfo);
+ icon.alt = '';
+ wrapper.appendChild(icon);
+ }
if (!hideLabels && markerInfo.Title) {
const label = document.createElement('div');
@@ -259,10 +284,13 @@ export default function MapboxMapView({
const existingMarkerState = markerRefs.current.get(markerInfo.Id);
const appearanceChanged =
!existingMarkerState ||
- existingMarkerState.title !== markerInfo.Title ||
- existingMarkerState.imagePath !== markerInfo.ImagePath ||
- existingMarkerState.infoWindowContent !== markerInfo.InfoWindowContent ||
- existingMarkerState.hideLabels !== hideLabels;
+ existingMarkerState.title !== markerInfo.Title ||
+ existingMarkerState.imagePath !== markerInfo.ImagePath ||
+ existingMarkerState.markerShape !== (markerInfo.Marker ?? '') ||
+ existingMarkerState.color !== (markerInfo.Color ?? '') ||
+ existingMarkerState.markerType !== markerInfo.Type ||
+ existingMarkerState.infoWindowContent !== markerInfo.InfoWindowContent ||
+ existingMarkerState.hideLabels !== hideLabels;
if (appearanceChanged) {
existingMarkerState?.marker.remove();
@@ -284,6 +312,9 @@ export default function MapboxMapView({
longitude: markerInfo.Longitude,
title: markerInfo.Title,
imagePath: markerInfo.ImagePath,
+ markerShape: markerInfo.Marker ?? '',
+ color: markerInfo.Color ?? '',
+ markerType: markerInfo.Type,
infoWindowContent: markerInfo.InfoWindowContent,
hideLabels,
});
diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/map/map.css b/Web/Resgrid.Web/Areas/User/Apps/src/components/map/map.css
index 8adb2234a..20f5ae033 100644
--- a/Web/Resgrid.Web/Areas/User/Apps/src/components/map/map.css
+++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/map/map.css
@@ -91,6 +91,20 @@
gap: 6px;
}
+.rg-map__layer-section + .rg-map__layer-section {
+ margin-top: 12px;
+ padding-top: 12px;
+ border-top: 1px solid #e5e7eb;
+}
+
+.rg-map__layer-swatch {
+ width: 12px;
+ height: 12px;
+ border: 1px solid rgba(17, 24, 39, 0.2);
+ border-radius: 999px;
+ flex: 0 0 auto;
+}
+
.rg-map__overlay {
position: absolute;
inset: 0;
@@ -127,6 +141,13 @@
cursor: pointer;
}
+.rg-map__marker--poi {
+ position: relative;
+ width: 36px;
+ min-height: 48px;
+ justify-content: flex-start;
+}
+
.rg-map__marker-icon {
width: 32px;
height: 37px;
@@ -134,6 +155,44 @@
pointer-events: none;
}
+.rg-map__poi-marker-wrapper {
+ background: transparent;
+ border: 0;
+}
+
+.rg-map__poi-marker {
+ position: relative;
+ width: 36px;
+ height: 48px;
+}
+
+.rg-map__poi-marker-shape {
+ width: 36px;
+ height: 48px;
+ fill: var(--rg-map-poi-color, #2563eb);
+ filter: drop-shadow(0 1px 2px rgba(17, 24, 39, 0.35));
+}
+
+.rg-map__poi-marker-icon {
+ position: absolute;
+ top: 10px;
+ left: 50%;
+ transform: translateX(-50%);
+ color: #ffffff;
+ font-size: 14px;
+ line-height: 1;
+ pointer-events: none;
+}
+
+.rg-map__marker--poi .rg-map__poi-marker-shape {
+ width: 36px;
+ height: 48px;
+}
+
+.rg-map__marker--poi .rg-map__poi-marker-icon {
+ top: 10px;
+}
+
.rg-map__marker-label {
max-width: 180px;
padding: 2px 6px;
diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/map/mapTypes.ts b/Web/Resgrid.Web/Areas/User/Apps/src/components/map/mapTypes.ts
index 4e85c7c07..280660ee8 100644
--- a/Web/Resgrid.Web/Areas/User/Apps/src/components/map/mapTypes.ts
+++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/map/mapTypes.ts
@@ -5,6 +5,7 @@ export const mapMarkerTypes = {
unit: 1,
station: 2,
personnel: 3,
+ poi: 4,
} as const;
export interface MapMarkerInfo {
@@ -16,7 +17,23 @@ export interface MapMarkerInfo {
ImagePath: string;
InfoWindowContent: string;
Color: string;
- Type: number;
+ Type: number | string;
+ Marker?: string;
+ PoiTypeId?: number | null;
+ PoiTypeName?: string;
+ Address?: string;
+ Note?: string;
+ LayerId?: string;
+ LayerName?: string;
+}
+
+export interface PoiLayerInfo {
+ PoiTypeId: number;
+ Name: string;
+ Color: string;
+ ImagePath: string;
+ Marker: string;
+ IsDestination: boolean;
}
export interface GetMapDataResult {
@@ -25,6 +42,7 @@ export interface GetMapDataResult {
CenterLon: number;
ZoomLevel: number;
MapMakerInfos: MapMarkerInfo[];
+ PoiLayers?: PoiLayerInfo[];
};
}
@@ -94,11 +112,23 @@ export interface MapRendererProps {
markers: MapMarkerInfo[];
layers: NormalizedMapLayer[];
layerVisibility: Record