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

Engines ​

TacticalDraw talks to a map through MapAdapter. Choose the adapter package for your engine; the rest of your TacticalDraw code stays the same.

Switch engines in the demo below. Each library loads only when selected.

Loading map…

Wrap your map with the matching adapter:

ts
new MapLibreAdapter(map); // maplibre-gl Map
new OpenLayersAdapter(map); // ol/Map
new LeafletAdapter(map); // leaflet Map

From there, new TacticalDraw(adapter), td.draw(...), and td.render(...) work identically. See the Quick start for a complete example.

Supported engines ​

EngineAdapter packageSupported versions
MapLibre GL JS@orbat-mapper/tactical-draw-adapter-maplibre5.8 or later, 6.x
OpenLayers@orbat-mapper/tactical-draw-adapter-openlayers7 or later
Leaflet@orbat-mapper/tactical-draw-adapter-leaflet1.9

Each engine is a peer dependency, so your app controls its version.

All three adapters render the same styles, labels, fill patterns, point symbols, and Images. Billboard pins are the exception: they require MapLibre GL JS 6 with WebGL2, and other engines show ordinary symbols.

Install ​

Install TacticalDraw, one adapter, and its peer map engine. No other engine packages are needed.

MapLibre GL ​

sh
pnpm add @orbat-mapper/tactical-draw @orbat-mapper/tactical-draw-adapter-maplibre maplibre-gl
sh
npm install @orbat-mapper/tactical-draw @orbat-mapper/tactical-draw-adapter-maplibre maplibre-gl
ts
import { TacticalDraw } from "@orbat-mapper/tactical-draw";
import { MapLibreAdapter } from "@orbat-mapper/tactical-draw-adapter-maplibre";
import * as maplibregl from "maplibre-gl";
import workerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url";
import "maplibre-gl/dist/maplibre-gl.css";

maplibregl.setWorkerUrl(workerUrl);
const map = new maplibregl.Map({ container, style, center, zoom });
map.on("load", () => {
  const td = new TacticalDraw(new MapLibreAdapter(map));
});

Create the adapter after the map's load event. MapLibre 6 needs its worker configured as shown; follow MapLibre's v5-to-v6 migration guide for your bundler. With MapLibre 5, omit the setWorkerUrl lines.

MapLibreAdapter accepts options as a second argument:

OptionDefaultDescription
viewChangeMode"continuous""continuous" refits screen-sized graphics, handles, and offset symbols on every frame of an animated zoom, rotate, or pitch. "settle" refits once when the animation ends, which is cheaper for large scenes.
terrainBandingtrueWith terrain active, paints all fills and lines in one band below points, icons, text, and pins, so terrain draping takes few passes. false keeps exact per-graphic paint order at one draping pass per graphic.
pinPixelRatiomap ratio, ≤ 2Device pixels per CSS pixel used to rasterize pin symbols. Raise it for sharp offscreen renders above 2×.
ts
new MapLibreAdapter(map, { viewChangeMode: "settle" });

OpenLayers ​

sh
pnpm add @orbat-mapper/tactical-draw @orbat-mapper/tactical-draw-adapter-openlayers ol
sh
npm install @orbat-mapper/tactical-draw @orbat-mapper/tactical-draw-adapter-openlayers ol
ts
import { TacticalDraw } from "@orbat-mapper/tactical-draw";
import { OpenLayersAdapter } from "@orbat-mapper/tactical-draw-adapter-openlayers";
import OLMap from "ol/Map";
import "ol/ol.css";

const map = new OLMap({ target, layers, view });
const td = new TacticalDraw(new OpenLayersAdapter(map));

OpenLayersAdapter accepts { viewChangeMode: "continuous" | "settle" } as a second argument, with the same meaning as for MapLibre. OpenLayers dispatches clicks on singleclick, so a click fires after a short delay that distinguishes it from a double-click.

Leaflet ​

sh
pnpm add @orbat-mapper/tactical-draw @orbat-mapper/tactical-draw-adapter-leaflet leaflet
sh
npm install @orbat-mapper/tactical-draw @orbat-mapper/tactical-draw-adapter-leaflet leaflet
ts
import { TacticalDraw } from "@orbat-mapper/tactical-draw";
import { LeafletAdapter } from "@orbat-mapper/tactical-draw-adapter-leaflet";
import L from "leaflet";
import "leaflet/dist/leaflet.css";

const map = L.map(target, { center, zoom });
const td = new TacticalDraw(new LeafletAdapter(map));

LeafletAdapter takes no options. Screen-sized graphics refit after Leaflet's zoom animation finishes rather than during it.

Use a different map engine ​

For another engine, extend BaseMapAdapter and implement the remaining MapAdapter methods. The adapter surface lists them, and the conformance suites in @orbat-mapper/tactical-draw/testing check your implementation against the same tests as the built-in adapters.