Skip to main content

Map Component

Introduction​

The Map Component renders an inline Google Maps view for CXTMS app modules. It plots markers from either an explicit markers array or a dispatch route/template stops array, can draw live track paths, ignores invalid or ungeocoded coordinates, and can fire actions when a marker is clicked. It can also periodically refresh the datasource or form that owns its data.

The component loads Google Maps with the organization-specific API key from configuration. If the key is unavailable, the component shows an unavailable state instead of rendering a blank map.

YAML Structure​

component: map
name: routeMap
props:
type: google
height: 520
center:
lat: 41.8781
lng: -87.6298
zoom: 10
fitBounds: true
showUnmappedNote: true
showInfoWindow: true
stops: "{{ route.stops }}"
markers:
- id: stop-1
label: "1. Warehouse"
lat: 41.8781
lng: -87.6298
address: "Chicago, IL"
color: success
text: "D1"
paths:
- label: "Driver 7 - today"
color: primary
width: 4
gapMinutes: 10
points: "{{ driverTrack.points }}"
refreshInterval: 30000
refreshHandler: driverTrack
onMarkerClick:
- setStore:
selectedStop: "{{ result }}"

Props​

PropTypeDefaultDescription
typestringgoogleMap provider. Only google is currently supported.
heightnumber | string520Map viewport height.
centerobjectautoOptional { lat, lng } center. Values may be numbers or numeric strings.
zoomnumber4 or autoInitial zoom. A single marker defaults to zoom 14; fitted multi-marker maps clamp at zoom 15.
markersarray-Explicit marker list. Takes precedence over stops.
stopsarray-Dispatch route/template stops. Converted to markers using each stop contact's shipping address.
pathsarray-Polyline definitions; each accepts points, color, width, dashed, gapMinutes, and label.
fitBoundsbooleantrueAuto-fit the viewport to all valid markers when no explicit center is provided.
showUnmappedNotebooleantrueShow a caption listing markers/stops that could not be plotted.
showInfoWindowbooleantrueShow an info window when a marker, or a path with a label, is clicked.
onMarkerClickaction[]-Actions fired after a marker click. Receives the clicked marker as result.
refreshIntervalnumber-Periodically refresh map data, in milliseconds. Values below 1000 are ignored.
refreshHandlerstring | string[]enclosing formDatasource, grid, collection, list, or form signal target(s) refreshed by the timer.

Marker Shape​

id: stop-1
number: 1
label: "1. Warehouse"
lat: 41.8781
lng: -87.6298
address: "Chicago, IL"
stopType: Pickup
color: success
text: D1

lat and lng can be numbers or numeric strings. Coordinates outside valid latitude/longitude ranges are treated as unmapped. Coordinates at 0,0 are also treated as unmapped because route stops use that as a create-time default before geocoding.

Set color to a theme palette key (primary, secondary, success, warning, error, or info) or a CSS color to draw a colored teardrop pin. text replaces the sequence number inside the pin. Without color, the standard Google pin is retained.

Paths and Data Gaps​

Each path contains ordered points with lat and lng; points may optionally carry an ISO recordedAt timestamp. Invalid, out-of-range, and 0,0 points are skipped.

paths:
- label: "Driver 7 - today"
color: primary
width: 4
dashed: false
gapMinutes: 10
points:
- { lat: 40.71, lng: -74.00, recordedAt: "2026-10-21T08:00:00Z" }
- { lat: 40.72, lng: -74.01, recordedAt: "2026-10-21T08:15:00Z" }

color accepts the same theme palette keys as markers or any CSS color; width defaults to 4 pixels. Set dashed: true to render the whole path dashed. When consecutive timestamped points are more than gapMinutes apart, the component draws that gap as a separate dashed warning-colored segment so missing telemetry does not look like a continuous drive. Points without parseable timestamps remain continuous.

Auto-fit includes both markers and path points. It runs initially and again when data identity changes (marker IDs, path count, or a path's first point), but not merely because live positions or path tails update. After the user pans or zooms, auto-fit remains off until that identity changes.

Periodic Refresh​

The map does not own a query. refreshInterval asks the component that loaded its data to refresh through existing SDUI signals:

- component: datasource
name: driverTrack
props:
queries: []
children:
- component: map
props:
paths: "{{ driverTrack.paths }}"
refreshInterval: 30000
refreshHandler: driverTrack

Each tick dispatches both refresh and reload to every configured target. Without refreshHandler, the map targets its enclosing form using the form's reloadHandler, then refreshHandler, then form name. Outside a form there is no implicit target. A form with unsaved changes is skipped, including when addressed through one of its signal names, so polling cannot discard edits. Timers pause while the browser tab is hidden and refresh once when it becomes visible again.

Stop Mapping​

When markers is not supplied, stops are converted into markers from:

  • dispatchRouteStopId or dispatchRouteTemplateStopId as id
  • stop position as number
  • stopContact.name as the marker label
  • stopContact.shipping.latitude / longitude as coordinates
  • stopContact.shipping.addressLine as the info-window address
  • stopType for display in the info window

Deleted stops (isDeleted: true) are skipped.

Examples​

Route stops map​

component: map
name: dispatchRouteMap
props:
height: 560
stops: "{{ dispatchRoute.stops }}"
fitBounds: true
onMarkerClick:
- setStore:
selectedStopId: "{{ result.id }}"

Explicit markers​

component: map
name: terminalMap
props:
height: 420
center:
lat: 33.749
lng: -84.388
zoom: 8
markers:
- id: atl
label: Atlanta Terminal
lat: 33.749
lng: -84.388
address: "Atlanta, GA"
- id: sav
label: Savannah Terminal
lat: 32.0809
lng: -81.0912
address: "Savannah, GA"
showUnmappedNote: false

Best Practices​

  • Use markers when the module already has normalized location objects.
  • Use stops for dispatch route and route template screens so marker numbering matches stop order.
  • Keep fitBounds: true unless the module needs a fixed map region.
  • Handle onMarkerClick for drill-in workflows, side-panel selection, or syncing a selected stop with the rest of the screen.
  • Make sure the organization has apps.google.googleMapsApiKey configured before relying on the component in production.