TacticalMap (Next)
Renders tracked entities (crew vehicle, targets) as NATO-style symbols on a static, per-range background image rather than tiled map imagery. Built for ranges that have no internet access at runtime, unlike MapDisplay, which loads tiles from a mapURL.
Dashboard generation
| Value | |
|---|---|
| Runner node | dashboard-v2 |
| Frontend | ui/dashboard (TacticalMapDS -> TacticalMap) |
| Data envelope | $heat-dataservice (contract) |
Layout component identifier
TacticalMap: the value of configuration.component in v2 layout rows.
Layout configuration
| Field | Description |
|---|---|
component | "TacticalMap" |
name | Internal name |
titleContent | Panel title |
channels | Channel id(s) bound to this widget, mapdisplay shape |
defaultRealm | Realm for data lookup |
showOpenModalButton | Expand to modal |
tacticalMapItem
The background image, its bounds and how turret yaw is read are set per layout in configuration.tacticalMapItem:
| Key | Required | Description |
|---|---|---|
backgroundImgUrl | Yes | Range background image, for example /env-assets/maps/<site>/v1/range.jpg uploaded to Control Centre scratch public/ |
rangeBounds | Yes | { minLat, minLon, maxLat, maxLon } in WGS84 degrees: the image’s geographic extent, used to project every point |
turretYawReference | No | How movement[].yaw is expressed. "absolute" (default): a compass bearing, clockwise from north, like heading. "relative": the turret angle relative to the hull, clockwise; the cone is drawn at heading + yaw. |
There is no tile URL, zoom or cone styling to set.
Data contract
Envelope
Publish canonical $heat-dataservice with realms, groups, and channels per the dashboard-v2 upstream contract.
Map channel
| Property | Value |
|---|---|
shape | "mapdisplay" |
data | Same movements[] envelope as MapDisplay |
TacticalMap reads the same mapdisplay channel shape as MapDisplay, but interprets each movement point differently and requires more fields:
| Field | Required | Description |
|---|---|---|
movements[].entityConfig | Yes | { allegiance, domain, unitType }. A movement with no entityConfig is silently dropped, not shown with a generic icon. |
movements[].movement[].latitude/longitude | Yes | Real WGS84 degrees. Projected against the fixed range image bounds, so a session that took place outside that range will not land correctly on the image. |
movements[].movement[].health | No | 0-100. A target’s health reaching 0 removes its marker from the map (see TacticalMap.tsx’s visibleTargets filter). |
movements[].movement[].heading | No | Compass degrees, clockwise from north: hull orientation. Drives marker rotation for tracked vehicles. |
movements[].movement[].yaw | No | Turret orientation. A compass bearing by default, or relative to the hull when tacticalMapItem.turretYawReference is "relative". Drives the vision-cone rotation; falls back to heading when absent. |
movements[].movement[].engagementType | No | For example "fire", "lase" or "kill". Marks that point with a permanent red cross on the map (no caption). Any non-empty value renders the same marker. |
movements[].movement[].engagementTargetId | No | Which target an engagement point targeted, if known. |
entityConfig’s allegiance/domain/unitType are the same enums as NatoSymbol . There is no channel-level affiliation source in the underlying capture (protobuf unit_type_data carries no friend/hostile field), so entityConfig has to be assigned upstream, in the arbex/processor script that builds the channel, not inferred by the frontend.
Example channel payload
{
"id": "tactical-map-tracks",
"name": "tactical-map-tracks",
"groupId": "map",
"shape": "mapdisplay",
"data": {
"movements": [
{
"name": "Puma",
"entityConfig": { "allegiance": "friend", "domain": "ground", "unitType": "tank" },
"movement": [
{
"latitude": "53.4701",
"longitude": "8.3850",
"heading": "45",
"yaw": "60",
"health": "100",
"capturedDate": "2026-08-17T11:56:40.029Z"
}
]
},
{
"name": "land_zbt_scheibe_58_pzturm_falling (482)",
"entityConfig": { "allegiance": "hostile", "domain": "ground", "unitType": "tank" },
"movement": [
{
"latitude": "53.4712",
"longitude": "8.3862",
"heading": "0",
"health": "100",
"capturedDate": "2026-08-17T11:56:40.029Z"
},
{
"latitude": "53.4712",
"longitude": "8.3862",
"heading": "0",
"health": "0",
"engagementType": "fire",
"capturedDate": "2026-08-17T11:58:12.500Z"
}
]
}
]
}
}Behaviour notes
- Playback-driven, not a live-updating track.
TacticalMapDSsamples every target’s track at the same fraction of a shared session duration (viauseClockandinterpolateTrack), throttled to a 100ms cadence. It does not render a raw point-by-point trail; short-lived and long-lived targets are kept in sync against one shared timeline rather than each target’s own span. The reached-path polyline is drawn only for the tracked vehicle (afriendmovement with more than one point); other movements get no trail, so a static target does not show a grey dot under its marker. - Vision cone. Rendered for any non-hostile
entityConfig.allegiance. It points alongyaw(orheading + yawwhenturretYawReferenceis"relative"), falling back toheading. On the tracked vehicle the cone starts at the turret, and that point turns with the hull. - Popup. Hovering or clicking a marker shows its name, health and
Heading(hull, compass degrees). When the point has turret data it also showsTurret, the turret angle relative to the hull, clockwise (0 = straight ahead, 90 = right). The turret angle is worked out fromheadingandyawin either reference mode. - Tracked-vehicle marker. A friendly target with more than one track point renders as a rotating vehicle sprite (
VehicleMarker) instead of a NATO symbol. Everything else (hostile targets, single-point tracks) renders as aNatoSymbol. - No external tiles, no internet dependency. The background is a bundled static image (
public/assets/tactical-map/rme-range-map.png), matching the platform’s air-gapped runtime requirement.
Related
- MapDisplay (Next): tile-based map, different background and config model
- Next components index
- Dataservice migration status
- dashboard-v2 upstream contract
- Reference JSON:
tools/arbex/reference/next/TacticalMap.json