Adapters are the layer between the core of the library and the external mapping libraries (Leaflet, Google Maps etc).
In simple terms an adapter takes input events, passes them through to create geometries in the store and then passes them back to the Adapter to be rendered specifically for the mapping library.
Terra Draw comes with a set of built in Adapters that you can use out of the box:
Provider | Requires API Key | Class | Jump to |
---|---|---|---|
Leaflet | No | TerraDrawLeafletAdapter | Example |
MapLibre | No | TerraDrawMapLibreGLAdapter | Example |
OpenLayers | No | TerraDrawOpenLayersAdapter | Example |
Google Maps | Yes | TerraDrawGoogleMapsAdapter | Example |
Mapbox | Yes | TerraDrawMapboxGLAdapter | Example |
ArcGIS Maps | Yes | TerraDrawArcGISMapsSDKAdapter |
Each Adapter must be instantiated with the library map instance (using the map
property) and the map library itself (using the lib
property). This is so that Terra Draw can access the map library API without having to import it directly.
For TerraDrawMapLibreGLAdapter
for example:
// Import MapLibre Library
import maplibregl from "maplibre-gl";
// Create Map Instance
const map = new maplibregl.Map({
container: id,
style: 'https://demotiles.maplibre.org/style.json',
center: [lng, lat],
zoom: zoom,
});
// Create Adapter
const adapter = new TerraDrawMapLibreGLAdapter({
// Pass in the map instance
map,
});
To use an Adapter you need to pass it to the Terra Draw constructor using the adapter
property:
const draw = new TerraDraw({
adapter: adapter,
modes: [new TerraDrawRectangleMode()],
});
Important
Each Adapter must be instantiated with both map
and lib
properties.
Code examples for each of the available Adapters are provided below.
The following examples assumes that the both Terra Draw and the relevant mapping library have been added to your project using a package manager (i.e. NPM) that includes a build step (e.g. Webpack, Vite etc):
npm install terra-draw
npm install leaflet
Your HTML needs to contain a <div>
element with an id of map
, where the map will be rendered:
<div id="map"></div>
Tip
This container, with an id
of "map" is assumed to be present in all examples throughout the documentation.
The following code samples rely on some configuration values being defined. For example:
// Target element id
const id = "map";
// Initial longitude and latitude
const lng = -1.826252;
const lat = 51.179026;
// Initial zoom level
const zoom = 16;
Tip
See the Installation section for more information, including a full example of using Terra Draw without a build step.
//Import Leaflet
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
// Import Terra Draw
import {
TerraDraw,
TerraDrawLeafletAdapter,
TerraDrawFreehandMode,
} from "terra-draw";
// Create Map
const map = L.map(id, {
center: [lat, lng],
zoom: zoom,
});
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
// Create Terra Draw
const draw = new TerraDraw({
adapter: new TerraDrawLeafletAdapter({
lib: L,
map,
}),
modes: [new TerraDrawFreehandMode()],
});
// Start drawing
draw.start();
draw.setMode("freehand");
// Import MapLibre
import MapLibreGL from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
// Import Terra Draw
import {
TerraDraw,
TerraDrawMapLibreGLAdapter,
TerraDrawFreehandMode,
} from "terra-draw";
// Create Map
const map = new MapLibreGL.Map({
container: id,
style: {
version: 8,
sources: {
"osm-tiles": {
type: "raster",
tiles: ["https://tile.openstreetmap.org/{z}/{x}/{y}.png"],
tileSize: 256,
attribution:
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
},
},
layers: [
{
id: "osm-tiles",
type: "raster",
source: "osm-tiles",
},
],
},
center: [lng, lat],
zoom: zoom,
});
// Create Terra Draw
const draw = new TerraDraw({
adapter: new TerraDrawMapLibreGLAdapter({
map,
}),
modes: [new TerraDrawFreehandMode()],
});
// Start drawing
draw.start();
draw.setMode("freehand");
Important
There are some requirements for the Google Map Adapter to work correctly:
- The Google Maps API requires an
apiKey
property when loading the library. - The map element must have a id property set
- Because an OverlayView is created, which can only be done asynchronously, you must wait for the 'ready' event on the draw instance
// Import Google Maps
import { Loader } from "@googlemaps/js-api-loader";
// Import Terra Draw
import {
TerraDraw,
TerraDrawGoogleMapsAdapter,
TerraDrawFreehandMode,
} from "terra-draw";
// API key required
const apiKey = "<your_api_key>";
// Load Google Maps
const loader = new Loader({
apiKey,
version: "weekly",
});
loader.load().then((google) => {
// Create map element
const mapElement = document.getElementById(id) // The map element must have an id set for the adapter to work!
// Create the google map itself
const map = new google.maps.Map(mapElement, {
disableDefaultUI: true,
center: { lat, lng },
zoom: zoom,
clickableIcons: false,
});
// Once the map is loaded
map.addListener("projection_changed", () => {
// Create Terra Draw
const draw = new TerraDraw({
adapter: new TerraDrawGoogleMapsAdapter({
lib: google.maps,
map,
coordinatePrecision: 9,
}),
modes: [new TerraDrawFreehandMode()],
});
// Start drawing
draw.start();
// Unlike other adapters, the google adapter 'ready' event is required to be listened for
// because the adapter creates an OverlayView which is only ready asynchronously
draw.on('ready', () => {
draw.setMode("freehand");
})
});
});
import {
TerraDraw,
TerraDrawFreehandMode,
TerraDrawOpenLayersAdapter,
} from "terra-draw";
import Feature from "ol/Feature";
import GeoJSON from "ol/format/GeoJSON";
import Map from "ol/Map";
import View from "ol/View";
import { Circle, Stroke, Style } from "ol/style";
import { OSM, Vector as VectorSource } from "ol/source";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { fromLonLat, getUserProjection } from "ol/proj";
// Create map
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
],
target: 'map',
view: new View({
center: fromLonLat([0, 0]),
zoom: 2,
}),
controls: [],
});
map.once("postrender", () => {
// Create Terra Draw
const draw = new TerraDraw({
adapter: new TerraDrawOpenLayersAdapter({
lib: {
Feature,
GeoJSON,
Style,
VectorLayer,
VectorSource,
Stroke,
getUserProjection,
Circle,
Fill,
},
map,
coordinatePrecision: 9,
}),
modes: [new TerraDrawFreehandMode()],
});
// Start drawing
draw.start();
draw.setMode("freehand");
});
Important
MapboxGL JS requires an API key to be set in the mapboxgl.accessToken
property.
// Import MapBox GL
import mapboxgl from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";
// Import Terra Draw
import {
TerraDraw,
TerraDrawMapboxGLAdapter,
TerraDrawFreehandMode,
} from "terra-draw";
// API key required
const apiKey = "<your_access_token>";
// Create Map
mapboxgl.accessToken = apiKey;
const map = new mapboxgl.Map({
container: id,
style: {
version: 8,
sources: {
"osm-tiles": {
type: "raster",
tiles: ["https://tile.openstreetmap.org/{z}/{x}/{y}.png"],
tileSize: 256,
attribution:
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
},
},
layers: [
{
id: "osm-tiles",
type: "raster",
source: "osm-tiles",
},
],
},
center: [lng, lat],
zoom: zoom,
});
// Create Terra Draw
const draw = new TerraDraw({
adapter: new TerraDrawMapboxGLAdapter({
map,
}),
modes: [new TerraDrawFreehandMode()],
});
// Start drawing
draw.start();
draw.setMode("freehand");
See the Development guide for more information on creating custom Adapters.
Guides
- Getting Started
- Store
- Adapters
- Modes
- Styling
- Events
- Development
- Examples