🚧 These docs are a work in progress — content is incomplete and may change without notice.
Skip to content

TacticalDraw ​

@orbat-mapper/tactical-draw adds interactive drawing and editing to @orbat-mapper/control-measures. Its API is independent of frameworks and map engines, and it applies the correct draw rule for each control-measure kind.

Create it with a map adapter, then call render(), draw(), edit(), or the other methods below. You only install the adapter and engine your app uses.

The Quick start walks through a complete MapLibre setup.

Adapters

Choose one engine package: @orbat-mapper/tactical-draw-adapter-openlayers, -maplibre, or -leaflet. Each extends BaseMapAdapter. For another engine, implement the MapAdapter interface.

Operating principles ​

Four rules shape the API:

  1. Your app owns the data. Keep the authoritative Graphic[] and pass it to render(). TacticalDraw never mutates the array.
  2. TacticalDraw owns active interactions. While a draw() or edit() promise is pending, it manages the preview, guide, handles, pointer, abort behavior, and relevant map events.
  3. Only one interaction can be active. Starting a new draw or edit aborts the previous one with a TacticalDrawAbortError that has the reason "preempted".
  4. A kind selects the behavior. Pass a kind such as "block"; TacticalDraw finds its metadata, option type, draw rule, and generator automatically.

The verbs at a glance ​

VerbWhat it does
render(graphics)Reconcile the graphics layer against your authoritative list.
draw(draft, options?)Create a control measure interactively; resolves on commit.
edit(measure, options?)Reshape or transform (scale/rotate/move) a control measure; resolves on close.
editMany(graphics, options?)Transform several graphics at once as a group; resolves on close.
syncTransformGraphics(measures, options?)Synchronize a selection with a group transform. Start a transform if necessary.
onGraphicPick(handler)Subscribe to clicks on committed measures.
cancel()Abort the live draw or edit.

Await an interaction, save snapshot.graphic to your list, then call render(). Cancellations reject the promise; handle them with isTacticalDrawAbortError or ignoreAbort.

Render the list ​

render(measures) reconciles the map with your authoritative list. Call it after any list change. IDs must be unique; duplicates throw before the layer is updated.

ts
td.render(measures);

During an active interaction, render() uses these rules:

  • During a draw, only the graphics layer is touched; the preview is left intact.
  • During an edit, the edited measure is excluded from graphics (the preview owns its working copy).
  • If the edited measure disappears from the next list, the edit promise rejects with reason "removed".
  • If it stays but its style changes, the edit preview picks up the new style.

Pixel-sized symbols, zoom, and baking

Pixel-sized geometry and labels are screen-anchored during drawing and editing, so they retain a constant on-screen size as the view changes. On commit, they bake to meters by default using the finishing zoom. Pass sizeAnchor: "screen" to draw() or edit() to keep them zoom-aware.

Meter-sized geometry does not rerender on zoom. Adapters scale ground-anchored label text from its meter height and clamp it to the layer's textSizeMinPixels/textSizeMaxPixels range (8–24 px by default). Gesture coordinates are rounded to six decimals, or roughly 0.11 m at the equator.

Cancel and remove resources ​

cancel() aborts the current draw or edit with reason "session" and returns whether anything was active. Call destroy() before removing the map.

ts
cancelButton.onclick = () => td.cancel();

const unsubscribe = td.onGraphicPick(onPick);

function dispose() {
  unsubscribe(); // idempotent
  td.destroy(); // aborts with reason "destroyed" and removes owned layers
  adapter.destroy();
}

After destroy()

destroy() is idempotent. Afterward, public methods such as cancel() throw TacticalDrawDestroyedError, while activeSession remains null. TacticalDraw removes layers it created but leaves host-supplied layers intact.