Skip to main content
This page is the map itself: the data you give it, what the user draws, and what you get back. To fill the map from the LOCI frame index instead of your own boundaries, read Frames first — it produces the same work areas this page consumes.

Work areas

A work area is the polygon a user may collect data in, such as a frame. Create them from Esri JSON, GeoJSON or by hand, and set them on view.workAreas. Coordinates are [longitude, latitude]. To load work areas from LOCI frames instead, see Frames; frames you load can be saved on the device, see Packs.
three ways in
A work area starts hidden unless you pass initiallyVisible = true. Drawing needs at least one visible work area (Geofencing). The user’s choice of visible work areas is remembered per mapId. fromGeoJson also takes a single Feature or a bare geometry. A bare geometry needs an id, and you can read the id from a different property:
one feature
The id comes from the FRAME_ID property by default. Spatial references: query Esri with outSR=4326. Web Mercator is converted; any other spatial reference throws MapWorkAreaFormatException. Replace them with the property; show, hide and zoom with the controller:
work area commands
Each change raises WorkAreaVisibilityChanged. Invalid data throws MapWorkAreaFormatException from the factory.

Features and entries

A feature is one saved entry drawn on the map: a point, a line or a polygon. Build a MapFeature from each record you hold. Only id and geoJson are needed.
from your own records
Set your entries on view.features, or in a layer (Layers). Set them again whenever your data changes. LOCI does not store features: see Packs for what is cached. Tapping an entry calls onFeatureTap. The metadata has the entry id and the layer id as formName. Fly to an entry, or let the user move a point:
editing and zooming
While editing, a new position is accepted inside a visible work area, or within 200 m of the original point. hideEntries() and showEntries() hide and show every entry.

Layers

Set layers on view.layers. Layers let one map hold several kinds of data, such as houses (points), roads (lines) and plots (polygons). A layer owns its features and sets the shape the user draws while it is the active layer.
three layers
  • Drawing. Draw creates the active layer’s shape. Switching the layer cancels a drawing in progress.
  • Visibility. Every layer is shown by default. The Layers option shows or hides each layer and chooses the active one. It appears with two or more layers.
  • View-only layers. A layer with no geometry (DrawGeometry.NONE, the default) is shown but cannot be drawn into.
  • Results. DataFromMap.layerId says which layer a shape was drawn in. A tap on an entry reports the layer id as metadata.formName.
A layer rejects features that do not match its geometry. Setting view.layers throws MapLayerFormatException listing each one — for example Feature 7 is a point but layer "parcels" draws polygon. Watcher boundaries are exempt. Pass MapOptions(strictGeometry = false) to draw mismatched features anyway. Two layers with the same id always throw. Set the layers after onMapReady so the exception reaches you, or check first:
check before you pass
Switch and toggle layers on the controller. Setting layers again keeps the user’s visibility choices for layers that remain; a layer added after the first time starts hidden, so show it with controller.showLayer(id). Changes call onLayerChanged and onLayerVisibilityChanged.
layer commands
The first layer keeps the default look. Every other layer without a style of its own gets its own colour, the same on every run and on every platform. Recolour one in place; a colour you set overrides every style and is kept when you pass the layers again:
recolour a layer
With grouping on, the user can draw a boundary around entries. It raises GroupingDrawn (not DrawCompleted) and has no layer. Handle it with onSaveGrouping. The threshold counts entries over all layers.

What you get back

A finished shape arrives as a DataFromMap: in onDrawCompleted when it is drawn, or in onSave when the user presses Save.
handle the result

Drawing

drawing
startDrawing() returns a MapResult; it fails when no layer is chosen, or the layer is hidden or view-only (Errors). Each tap is checked in order — zoom 13 or closer (always), then the geofencing checks, then the grouping threshold when set. A failed check raises MapFailure and the tap is dropped. Points place at once; lines and polygons add a vertex, and a polygon closes when the user taps near its first point after at least three points.

Address verification

Pin mode places one pin, with no work areas and no geofencing. A tap calls onDrawCompleted with the tapped point.
pin mode

Events

Set a callback on the view for the events you need. onEvent receives every event, after the callback of its own.
callbacks
Controller users can listen with controller.addListener, which receives the same events. mode is NONE, PICKING_GEOMETRY, CATEGORIZING_GEOMETRY or NAVIGATING. LociMapView shows a MapFailure message as a toast; set view.showErrors = false to handle it yourself.

The controller

Use the controller for commands: drawing, zooming, showing and hiding. Get it as view.controller. Setup and results are properties and callbacks on the view (Work areas, Events). A command never throws. Commands that return nothing (such as attach, setLayers, setFeatures and undo) run once the map is ready, so you can call them at any time. Commands that return a MapResult (such as showLayer, startDrawing and zoomToFeature) fail with MapInitializationError until the map is ready — call them after onMapReady, or inside whenReady { }.
results
Current state is on controller.core:
state

Built-in controls

LociMapView draws these controls over the map. Each one calls a controller command. Rename with labels = LociMapLabels(key = "text"), hide with controls = LociMapControls(flag = false), or replace with builders = LociMapBuilders(...). While drawing, the options list is replaced by undo, redo and cancel.

Make it match your app

Colours are ARGB integers. Anything you leave out keeps its default.
rename, hide, recolour
A builder receives the context and the controller. This one replaces the zoom buttons with a single button:
replace one control

Geofencing

Every drawing is checked against the work areas: one must be visible, the point must be inside a visible one, and the user must be inside the same one. To try the map without being in a work area, switch the check off:
testing only
Do not ship enforceGeofencing = false. Data drawn outside a work area is accepted, and nothing marks it.
Grouping lets the user draw a boundary around entries and blocks further entries once a threshold is reached. It is off by default:
grouping
With it on, Group Entries appears while entries are ungrouped. When the threshold stops a draw, MapFailure.requiresGrouping is true. A rule of type form counts entries; any other type sums the columnName property.

Options and flags

Set MapOptions on view.options. Only mapId is required.
baseMaps

Styles

Colours are ARGB integers; in JSON, #RRGGBB or #AARRGGBB. Set styles in MapOptions, per layer, or later on the controller. A layer’s style takes priority over MapOptions.style. Constructors check the ranges; fromJson clamps or ignores bad values.
styles
A PNG replaces the drawn shape; it is scaled to sizeDp, and the number is drawn over it unless you turn it off with showLabel = false. Build a style from JSON, where missing or unreadable fields keep their defaults:
style.json
parse it

Errors

Every error extends MapError and has a message you can show. They arrive in onError or inside a failed MapResult. Bad work-area data throws MapWorkAreaFormatException straight from the factory, and bad layers throw MapLayerFormatException from setLayers, before anything reaches the map.
handle errors
These are the map’s own errors. The errors the SDK raises when it calls the LOCI API — rejected keys, rate limits, offline — are separate and live in Frames.