maplibre-gl-terradraw

repository·main·Indexed 41 days ago

https://github.com/watergis/maplibre-gl-terradraw

A plugin for MapLibre GL JS that integrates Terra Draw drawing capabilities, providing intuitive controls for drawing and measuring geographic features. Version 1.16.0 includes the MaplibreTerradrawControl for managing GeoJSON features, custom font glyph configuration for TextMode, and integration with the Terra Draw API.

Tokens
9.8K
Snippets
30
Records
39
Agent score
48%

What's inside maplibre-gl-terradraw

  1. Configure Valhalla Isochrone contours

    main

    When defining contours for the Valhalla Isochrone engine, you must provide either time or distance, but not both. Providing both will result in an error from the Valhalla API.

    • time: Specified in minutes.
    • distance: Specified in kilometers.
    • color: A HEX color string including the hash (e.g., #ff0000). The ValhallaIsochrone class automatically strips the # before sending the request to the API.

    Available ContourType values are 'time' and 'distance'.

    const contours: Contour[] = [
      { time: 15, color: '#ff0000' },
      { time: 30, color: '#ffff00' }
    ];
  2. Understand the ValhallaTripResult data structure

    main

    When the Valhalla API responds successfully, the data is mapped to the ValhallaTripResult interface. Key components include:

    • trip.locations: An array of ValhallaRoutingLocation objects (lat, lon, city, etc.).
    • trip.legs: An array of ValhallaRoutingLeg objects. Each leg contains maneuvers (instructions) and a shape (encoded geometry).
    • trip.summary: A ValhallaTripSummary containing total time, length, and cost.
    • id: The unique trip identifier.
  3. Enable elevation computation with terrain sources

    main

    To compute elevation for linestring nodes, set computeElevation: true in MeasureControlOptions. If you specify a terrainSource, the plugin will query elevation from that source.

    Note: You must manually add and enable a raster-dem source in your MapLibre style beforehand. For example, to use the Terrarium source from AWS:

    map?.addSource('terrarium', {
      type: 'raster-dem',
      attribution: '&copy; <a href="https://github.com/tilezen/joerd/blob/master/docs/attribution.md" target="_blank" rel="noopener">Tilezen Joerd</a>',
      tiles: [
        'https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'
      ],
      minzoom: 0, maxzoom: 5, tileSize: 256, encoding: 'terrarium', bounds: [-180, -90, 180, 90]
    });
    map?.setTerrain({source: 'terrarium', exaggeration: 1});

    If terrainSource is set to undefined, the plugin attempts to fetch the elevation from the terrain currently enabled in the MapLibre map.

  4. Configure MeasureControlOptions

    main

    The MeasureControlOptions interface is used to configure the MeasureControl plugin. It allows you to customize drawing modes, measurement units (metric/imperial), styling for MapLibre layers, keyboard shortcuts, and elevation computation settings.

    Key Configuration Categories

    Drawing Modes and Interaction

    • modes: An array of TerradrawMode[] defining which modes are available and their order. Default includes: ['render','point','linestring','polygon', 'rectangle','angled-rectangle','circle', 'freehand','sector','sensor', 'delete'].
    • open: Boolean to determine if the editor should be open by default.
    • showDeleteConfirmation: Boolean to show a popup when deleting features.
    • keyboardShortcuts: Configuration for activating modes via standard A-Z keys.
    • undoRedo: Configuration for modeLevel, sessionLevel, and keyboardShortcuts for TerraDraw undo/redo functionality.

    Measurement Units and Precision

    • measureUnitType: Sets the system to metric or imperial.
    • distanceUnit: Sets the distance unit or a custom conversion function.
    • areaUnit: Sets the area unit or a custom conversion function.
    • distancePrecision / areaPrecision: Numeric precision for displayed values.
    • measureUnitSymbols: A record to overwrite default unit symbols.

    MapLibre Layer Styling

    Use MapLibre layer specification objects to style the visual elements of the measurement tool:

    • pointLayerLabelSpec: For point layers.
    • lineLayerLabelSpec: For line distance labels.
    • routingLineLayerNodeSpec: For circle layer nodes on line distance layers.
    • polygonLayerSpec: For polygon area centroids.

    Elevation and Terrain

    • computeElevation: Boolean to enable/disable elevation calculation for linestring nodes.
    • terrainSource: Specifies the terrain source (e.g., terrainRGB or terrarium). If undefined, it attempts to use the enabled terrain from the MapLibre style.
    • elevationCacheConfig: Configuration for the elevation cache (maxSize, ttl, precision).
  5. Configure TextModeStyling for MapLibre labels

    main

    The TextModeStyling object defines how committed text labels appear in the {prefix}-text-labels MapLibre symbol layer. These properties are merged over the defaults provided by MaplibreTerradrawControl.

    PropertyTypeDescription
    pointColorHexColorAnchor point fill color.
    pointWidthnumberAnchor point radius in pixels. Default 0 (invisible).
    pointOutlineColorHexColorAnchor point outline color.
    pointOutlineWidthnumberAnchor point outline width.
    textColorHexColorMapLibre text-color. Default #000000.
    textSizenumberMapLibre text-size in pixels. Default 12.
    textSelectedSizenumberMapLibre selected text-size. Default 14.
    textHaloColorHexColorMapLibre text-halo-color. Default #3f97e0.
    textSelectedHaloColorHexColorMapLibre selected text-halo-color. Default #ffffff.
    textHaloWidthnumberMapLibre text-halo-width. Default 5.
    textFontstring[]MapLibre text-font (font stack). Default ['sans-serif']. Use a font existing in your map style glyphs.
  6. Configure the layer prefix via adapterOptions

    main

    The MaplibreTerradrawControl uses a prefixId to namespace its MapLibre layers and sources (e.g., for text labels and GeoJSON sources). By default, this prefix is 'td'. You can customize this prefix by providing adapterOptions.prefixId in the control's options. This is useful if you need to avoid naming collisions with other layers on your map.

    When customized, the control will look for and manage layers such as {prefixId}-text-labels and sources such as {prefixId}-text.

    // Example of setting a custom prefix
    const control = new MaplibreTerradrawControl({
      adapterOptions: {
        prefixId: 'my-custom-prefix'
      }
    });
  7. Control expansion and deletion confirmation

    main

    The MaplibreTerradrawControl has two specific configuration behaviors:

    1. Expansion State: Setting isExpanded to true or false toggles the visibility of the drawing mode buttons. Setting it to false also resets the active mode to render.
    2. Delete Confirmation: If showDeleteConfirmation is set to true in the options, a modal dialog will appear when the user attempts to delete all features or selected features.
    const drawControl = new MaplibreTerradrawControl({
      showDeleteConfirmation: true
    });
    
    // Programmatically expand/collapse the toolbar
    drawControl.isExpanded = true;
  8. Use TerraDrawTextMode for text labels

    main

    The TerraDrawTextMode allows users to place, edit, and drag freeform text labels on a MapLibre GL map. It creates Point GeoJSON features with a text property. The MaplibreTerradrawControl automatically renders these as a symbol layer using MapLibre's native text styling.

    Interaction Model

    GestureBehaviour
    Click on the mapOpens a textarea popup at the clicked location.
    Enter (or Submit button)Commits the label as a Point feature with a text property. Calls onTextCommit and fires the TerraDraw finish event.
    Shift+EnterInserts a newline without committing.
    Escape (in popup)Dismisses the popup and deletes the uncommitted feature.
    Click outside open popupCommits any typed text, or dismisses if empty.
    Click near existing labelOpens the textarea pre-filled with existing text (requires editable: true).
    Drag a committed labelHandled by TerraDrawSelectMode when flags.text.feature.draggable is true.

    Implementation Example

    import { MaplibreTerradrawControl, TerraDrawTextMode } from '@watergis/maplibre-gl-terradraw';
    
    const control = new MaplibreTerradrawControl({
      modes: ['text', 'select', 'delete'],
      modeOptions: {
        text: new TerraDrawTextMode({
          editable: true,
          placeholder: 'Add a label…',
          styles: {
            textColor: '#1a1a1a',
            textSize: 14,
            textSelectedSize: 16,
            textHaloColor: '#ffffff',
            textHaloWidth: 2,
            textSelectedHaloColor: '#E0B03F'
          },
          onTextCommit: (id, text) => console.log(`${id}: ${text}`),
        }),
      },
    });
    
    map.addControl(control, 'top-right');
    import { MaplibreTerradrawControl, TerraDrawTextMode } from '@watergis/maplibre-gl-terradraw';
    
    const control = new MaplibreTerradrawControl({
      modes: ['text', 'select', 'delete'],
      modeOptions: {
        text: new TerraDrawTextMode({
          editable: true,
          placeholder: 'Add a label…',
          styles: {
            textColor: '#1a1a1a',
            textSize: 14,
            textSelectedSize: 16,
            textHaloColor: '#ffffff',
            textHaloWidth: 2,
            textSelectedHaloColor: '#E0B03F'
          },
          onTextCommit: (id, text) => console.log(`${id}: ${text}`),
        }),
      },
    });
    
    map.addControl(control, 'top-right');
  9. Customize area unit conversion

    main

    You can provide a custom conversion function to the areaUnit property of MeasureControlOptions. The function receives the area value in square meters and must return an object with area and unit properties.

    const customConversion: AreaUnitCallBackType = (valueInSquareMeters) => {
       if (valueInSquareMeters >= 1000) {
         return { area: valueInSquareMeters / 1000, unit: 'km²' };
       } else {
         return { area: valueInSquareMeters, unit: 'm²' };
       }
    };
    
    // Applied to the control instance
    control.areaUnit = customConversion;