Skip to content

Latest commit

 

History

History
441 lines (363 loc) · 11.9 KB

3.ADAPTERS.md

File metadata and controls

441 lines (363 loc) · 11.9 KB

Adapters

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.

Available Adapters

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

Using an Adapter

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.

Examples

Code examples for each of the available Adapters are provided below.

Prerequisites

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.

Leaflet

//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:
    '&copy; <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");

MapLibre

// 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:
          '&copy; <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");

Google Maps

Important

There are some requirements for the Google Map Adapter to work correctly:

  1. The Google Maps API requires an apiKey property when loading the library.
  2. The map element must have a id property set
  3. 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");
    })
  });
});

OpenLayers

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("rendercomplete", () => {
    // 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");
});

Mapbox

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:
          '&copy; <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");

ArcGIS

import EsriMap from "@arcgis/core/Map";
import MapView from "@arcgis/core/views/MapView.js";
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer";
import Point from "@arcgis/core/geometry/Point";
import Polyline from "@arcgis/core/geometry/Polyline";
import ArcGISPolygon from "@arcgis/core/geometry/Polygon";
import Graphic from "@arcgis/core/Graphic";
import SimpleFillSymbol from "@arcgis/core/symbols/SimpleFillSymbol";
import SimpleLineSymbol from "@arcgis/core/symbols/SimpleLineSymbol";
import Color from "@arcgis/core/Color";
import SimpleMarkerSymbol from "@arcgis/core/symbols/SimpleMarkerSymbol";

// Create an OSM basemap
const map = new EsriMap({
  basemap: "osm", // Basemap layer service
});

// Create a ArcGIS MapView object with the configured center/zoom etc
const view = new MapView({
  map: map,
  center: [0, 0], // Longitude, latitude
  zoom: 12, // Zoom level
  container: 'esri-map', // Div element
});

// Create the Terra Draw instance with the ArcGIS Adapter
const draw = new TerraDraw({
  adapter: new TerraDrawArcGISMapsSDKAdapter({
    lib: {
      GraphicsLayer,
      Point,
      Polyline,
      Polygon: ArcGISPolygon,
      Graphic,
      SimpleLineSymbol,
      SimpleFillSymbol,
      SimpleMarkerSymbol,
      Color,
    },
    map: view,
  }),
  modes: [new TerraDrawFreehandMode()],
});


// Start drawing
draw.start();
draw.setMode("freehand");

Creating Custom Adapters

See the Development guide for more information on creating custom Adapters.


Guides

  1. Getting Started
  2. Store
  3. Adapters
  4. Modes
  5. Styling
  6. Events
  7. Development
  8. Examples