Skip to content

Custom Layers

In addition to built-in layers, the SDK also supports adding custom layers, allowing you to flexibly display your own data on the map.

Adding Custom Layers

Basic Usage

javascript
// 1. Add data source
sdk.addSource("custom-source", {
  type: "geojson",
  data: {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        geometry: {
          type: "Point",
          coordinates: [116.3974, 39.9093],
        },
        properties: {
          name: "Custom Point",
        },
      },
    ],
  },
});

// 2. Add layer
sdk.addLayer({
  id: "custom-layer",
  source: "custom-source",
  type: "circle",
  paint: {
    "circle-radius": 8,
    "circle-color": "#ff0000",
  },
});

Using LayerManager

javascript
// Use LayerManager to add layer
const layerId = sdk.layerManager.addLayer({
  id: "custom-layer",
  source: "custom-source",
  type: "circle",
  paint: {
    "circle-radius": 8,
    "circle-color": "#ff0000",
  },
});

console.log("Layer ID:", layerId);

Layer Types

Circle

javascript
sdk.addLayer({
  id: "circle-layer",
  source: "points-source",
  type: "circle",
  paint: {
    "circle-radius": 10,
    "circle-color": "#ff0000",
    "circle-stroke-width": 2,
    "circle-stroke-color": "#ffffff",
    "circle-opacity": 0.8,
  },
});

Line

javascript
sdk.addLayer({
  id: "line-layer",
  source: "lines-source",
  type: "line",
  paint: {
    "line-color": "#007bff",
    "line-width": 2,
    "line-opacity": 0.8,
    "line-dasharray": [2, 2],
  },
});

Fill

javascript
sdk.addLayer({
  id: "fill-layer",
  source: "polygons-source",
  type: "fill",
  paint: {
    "fill-color": "#007bff",
    "fill-opacity": 0.5,
    "fill-outline-color": "#000000",
  },
});

Symbol

javascript
// Register icon first
sdk.registerIcon("custom-icon", iconImage, {
  pixelRatio: 1,
});

// Add symbol layer
sdk.addLayer({
  id: "symbol-layer",
  source: "points-source",
  type: "symbol",
  layout: {
    "icon-image": "custom-icon",
    "icon-size": 1,
    "text-field": ["get", "name"],
    "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
    "text-size": 12,
  },
  paint: {
    "text-color": "#000000",
  },
});

Heatmap

javascript
sdk.addLayer({
  id: "heatmap-layer",
  source: "points-source",
  type: "heatmap",
  paint: {
    "heatmap-weight": 1,
    "heatmap-intensity": 1,
    "heatmap-color": [
      "interpolate",
      ["linear"],
      ["heatmap-density"],
      0,
      "rgba(0,0,255,0)",
      0.1,
      "royalblue",
      0.3,
      "cyan",
      0.5,
      "lime",
      0.7,
      "yellow",
      1,
      "red",
    ],
    "heatmap-radius": 30,
    "heatmap-opacity": 0.6,
  },
});

Source Types

GeoJSON Source

javascript
sdk.addSource("geojson-source", {
  type: "geojson",
  data: {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        geometry: {
          type: "Point",
          coordinates: [116.3974, 39.9093],
        },
        properties: {},
      },
    ],
  },
});

Vector Tile Source

javascript
sdk.addSource("vector-source", {
  type: "vector",
  tiles: [
    "https://example.com/tiles/{z}/{x}/{y}.pbf",
  ],
  minzoom: 0,
  maxzoom: 14,
});

Raster Tile Source

javascript
sdk.addSource("raster-source", {
  type: "raster",
  tiles: [
    "https://example.com/tiles/{z}/{x}/{y}.png",
  ],
  tileSize: 256,
});

Image Source

javascript
sdk.addSource("image-source", {
  type: "image",
  url: "https://example.com/image.jpg",
  coordinates: [
    [116.0, 40.0], // Top left
    [117.0, 40.0], // Top right
    [117.0, 39.0], // Bottom right
    [116.0, 39.0], // Bottom left
  ],
});

Video Source

javascript
sdk.addSource("video-source", {
  type: "video",
  urls: [
    "https://example.com/video.mp4",
  ],
  coordinates: [
    [116.0, 40.0],
    [117.0, 40.0],
    [117.0, 39.0],
    [116.0, 39.0],
  ],
});

Layer Styles

Circle Layer Properties

Layout Properties

PropertyTypeDefaultDescription
circle-sort-keynumber-Controls layer sort order, sorts features in ascending order by this value. Features with larger sort key values have higher display priority
visibility"visible" | "none""visible"Controls layer visibility

Paint Properties

PropertyTypeDefaultDescription
circle-radiusnumber5Controls circle radius
circle-colorcolor"#000000"Controls circle fill color
circle-blurnumber0Controls circle blur
circle-opacitynumber1Controls circle opacity (0-1)
circle-translate[number, number][0, 0]Controls circle offset
circle-translate-anchor"map" | "viewport""map"Controls circle translate anchor. map means translated relative to map, viewport means translated relative to viewport
circle-pitch-scale"map" | "viewport""map"Controls circle scaling behavior when map is tilted. map circles scale based on visual distance from camera, viewport circles don't scale with map tilt
circle-pitch-alignment"map" | "viewport""map"Controls circle alignment when map is tilted. map circles align with map plane, viewport circles align with viewport
circle-stroke-widthnumber0Controls circle stroke width
circle-stroke-colorcolor"#000000"Controls circle stroke color
circle-stroke-opacitynumber1Controls circle stroke opacity (0-1)

Line Layer Properties

Layout Properties

PropertyTypeDefaultDescription
line-cap"butt" | "round" | "square""butt"Controls line cap style. butt: flat ends; round: round ends; square: square ends
line-join"miter" | "round" | "bevel""miter"Controls line join style. miter: sharp corner; round: round join; bevel: beveled join
line-miter-limitnumber2Controls maximum angle at line join
line-round-limitnumber1.05Controls maximum angle at round join
line-sort-keynumber-Controls line drawing order in layer, sorts features in ascending order by this value. Features with larger sort key values have higher display priority
visibility"visible" | "none""visible"Controls layer visibility

Paint Properties

PropertyTypeDefaultDescription
line-blurnumber0Controls line blur
line-opacitynumber1Controls line opacity (0-1)
line-translate[number, number][0, 0]Controls line translation
line-translate-anchor"map" | "viewport""map"Controls line translate anchor
line-colorcolor"#000000"Controls line color
line-widthnumber1Controls line width
line-gap-widthnumber0Controls line gap width
line-offsetnumber0Controls line offset. Positive values offset line to the right relative to its direction, negative values offset to the left
line-dasharraynumber[]-Controls line dash pattern, disabled by line-pattern. Defines alternating dash and gap lengths. Array values are scaled by line width
line-patternresolvedImage-Controls line pattern, specifies image name in sprite for drawing image lines. For seamless patterns, image width must be power of 2 (2, 4, 8, ..., 512 pixels)
line-gradientcolor-Controls line gradient, disabled by line-dasharray and line-pattern, only supports GeoJSON type sources

Fill Layer Properties

Layout Properties

PropertyTypeDefaultDescription
fill-sort-keynumber-Controls layer sort order, sorts features in ascending order by this value. Features with larger sort key values have higher display priority
visibility"visible" | "none""visible"Controls layer visibility

Paint Properties

PropertyTypeDefaultDescription
fill-antialiasbooleantrueControls fill antialiasing
fill-opacitynumber1Controls fill opacity (0-1)
fill-colorcolor"#000000"Controls fill color, disabled by fill-pattern
fill-outline-colorcolor"#000000"Controls fill outline color, disabled by fill-pattern, requires fill-antialias to be true
fill-translate[number, number][0, 0]Controls fill translation
fill-translate-anchor"map" | "viewport""map"Controls fill translate anchor
fill-patternresolvedImage-Controls fill pattern, specifies image name in sprite for drawing image fill. For seamless patterns, image width must be power of 2 (2, 4, 8, ..., 512 pixels)

Symbol Layer Properties

Layout Properties

Symbol Placement
PropertyTypeDefaultDescription
symbol-placement"line" | "line-center" | "point""point"Symbol placement. point places at geometry point; line places along geometry lines, only for LineString and Polygon; line-center places at line center, only for LineString and Polygon
symbol-spacingnumber250Symbol spacing (pixels), requires symbol-placement to be line
symbol-avoid-edgesbooleanfalseSymbol edge avoidance. If true, symbols (icons, labels) won't cross vector tile boundaries to avoid collisions
symbol-sort-keynumber-Controls layer sort order, sorts features in ascending order by this value. Features with larger sort key values have higher display priority
Icon Properties
PropertyTypeDefaultDescription
icon-imageresolvedImage-Icon image, image name in sprite for drawing image background
icon-sizenumber1Controls icon size
icon-rotatenumber0Icon rotation angle, requires icon-image
icon-paddingpadding2Icon padding, requires icon-image
icon-keep-uprightbooleanfalseIf true, icon may flip to prevent upside-down rendering. Requires icon-image, icon-rotation-alignment to be map, and symbol-placement to be line or line-center
icon-offset[number, number][0, 0]Icon offset, requires icon-image
icon-anchor"center" | "left" | "right" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right""center"Icon anchor, requires icon-image
icon-rotation-alignment"map" | "viewport" | "auto""map"Controls icon rotation alignment. map: when symbol-placement is point, icon aligns east-west; when symbol-placement is line or line-center, icon x-axis aligns with line. viewport: icon x-axis aligns with viewport x-axis regardless of symbol-placement. auto: when symbol-placement is point, same as viewport; when symbol-placement is line or line-center, same as map
icon-pitch-alignment"map" | "viewport" | "auto""auto"Icon pitch alignment. map: icon parallel to map; viewport: icon parallel to viewport; auto: automatically matches icon-rotation-alignment value
icon-text-fit"none" | "width" | "height" | "both""none"Controls icon text fit. none: no adjustment; width: icon scales in x-dimension to fit text width; height: icon scales in y-dimension to fit text height; both: icon scales in both x and y dimensions
icon-text-fit-padding[number, number, number, number][0, 0, 0, 0]Controls icon text fit, requires icon-image, text-field, and icon-text-fit to be both, width, or height
icon-allow-overlapbooleanfalseControls whether icon allows overlap, requires icon-image, disabled by icon-overlap. If true, icon will allow overlap
icon-overlap"never" | "always" | "cooperative""never"Controls icon overlap mode, requires icon-image. never: icon hidden if overlaps with any previously drawn symbol; always: icon shown even if overlaps; cooperative: checks symbol overlap mode if collision occurs
icon-ignore-placementbooleanfalseControls whether icon is covered by other icons or text. If true, other symbols may be visible even if overlapping with icon
icon-optionalbooleanfalseControls icon visibility. If true, when icon conflicts but text doesn't, text shows without corresponding icon
Text Properties
PropertyTypeDefaultDescription
text-fieldstring""Text content
text-fontstring[]["Open Sans Regular", "Arial Unicode MS Regular"]Text font
text-sizenumber16Text size
text-max-widthnumber10Text max width
text-line-heightnumber1.2Text line height
text-letter-spacingnumber0Text letter spacing
text-justify"auto" | "left" | "center" | "right""center"Text alignment. auto: text aligns toward anchor; left: left align; center: center align; right: right align
text-rotation-alignment"map" | "viewport" | "viewport-glyph" | "auto""auto"Text rotation mode. map: when symbol-placement is point, text aligns east-west; when symbol-placement is line or line-center, text x-axis aligns with line. viewport: glyph x-axis aligns with viewport x-axis regardless of symbol-placement. viewport-glyph: when symbol-placement is point, text aligns with viewport x-axis; when symbol-placement is line or line-center, glyph aligns with viewport x-axis and placed along line. auto: when symbol-placement is point, same as viewport; when symbol-placement is line or line-center, same as map
text-pitch-alignment"map" | "viewport" | "auto""auto"Text pitch alignment. map: text parallel to map; viewport: text parallel to viewport; auto: automatically matches text-rotation-alignment value
text-anchor"center" | "left" | "right" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right""center"Part of the text placed closest to the anchor. center: center of text; left: left side; right: right side; top: top; bottom: bottom; top-left: top-left corner; top-right: top-right corner; bottom-left: bottom-left corner; bottom-right: bottom-right corner. Requires text-field, disabled by text-variable-anchor
text-offset[number, number][0, 0]Offset distance of text from its anchor (units: em). Requires text-field, disabled by text-radial-offset. Positive values indicate right and down, negative values indicate left and up
text-radial-offsetnumber0Radial offset of text in the direction of the symbol's anchor (units: em). Requires text-field. Useful in combination with text-variable-anchor, which defaults to using the two-dimensional text-offset if present
text-variable-anchorstring[]-Array of text anchor locations to increase the chance of placing high-priority labels on the map. The renderer will attempt to place the label at each location, in order, before moving onto the next label. Requires text-field and symbol-placement to be point
text-variable-anchor-offsetarray-Array of text anchor locations, each paired with an offset value. Requires text-field and symbol-placement to be point. Array length must be even and alternate between enum and point entries
text-rotatenumber0Rotates the text clockwise (units: degrees). Requires text-field
text-transform"none" | "uppercase" | "lowercase""none"Specifies how to capitalize text, similar to CSS text-transform property. none: text not altered; uppercase: forces all letters to uppercase; lowercase: forces all letters to lowercase. Requires text-field
text-paddingnumber2Size of the additional area around the text bounding box used for detecting symbol collisions (units: pixels). Requires text-field
text-max-anglenumber45Maximum angle change between adjacent characters (units: degrees). Requires text-field and symbol-placement to be line or line-center
text-writing-modestring[]-Controls a symbol's orientation. Requires text-field and symbol-placement to be point
text-keep-uprightbooleantrueIf true, the text may be flipped vertically to prevent it from being rendered upside-down. Requires text-field, text-rotation-alignment to be map, and symbol-placement to be line or line-center
text-allow-overlapbooleanfalseControls whether text allows overlap, requires text-field, disabled by text-overlap. If true, text will allow overlap
text-overlap"never" | "always" | "cooperative""never"Controls text overlap mode, requires text-field. never: text hidden if overlaps with any previously drawn symbol; always: text shown even if overlaps; cooperative: checks symbol overlap mode if collision occurs
text-ignore-placementbooleanfalseControls whether text is covered by other icons or text. If true, other symbols may be visible even if overlapping with text
text-optionalbooleanfalseControls text visibility. If true, when text conflicts but icon doesn't, icon will display without corresponding text
visibility"visible" | "none""visible"Controls layer visibility

Paint Properties

PropertyTypeDefaultDescription
text-colorcolor"#000000"Text color, requires text-field
text-halo-colorcolor"rgba(0, 0, 0, 0)"The color of the text's halo, which helps it stand out from backgrounds, requires text-field
text-halo-widthnumber0Distance of halo to the font outline (units: pixels), requires text-field. Max text halo width is 1/4 of the font-size
text-halo-blurnumber0The halo's fadeout distance towards the outside (units: pixels), requires text-field
text-opacitynumber1Text opacity (0-1), requires text-field
text-translate[number, number][0, 0]Distance that the text's anchor is moved from its original placement (units: pixels), requires text-field. Positive values indicate right and down, negative values indicate left and up
text-translate-anchor"map" | "viewport""map"Controls the frame of reference for text-translate, requires text-field and text-translate. map: text translated relative to map; viewport: text translated relative to viewport

Paint Property Examples

javascript
sdk.addLayer({
  id: "styled-layer",
  source: "source-id",
  type: "circle",
  paint: {
    // Basic properties
    "circle-radius": 10,
    "circle-color": "#ff0000",
    "circle-opacity": 0.8,
    
    // Stroke properties
    "circle-stroke-width": 2,
    "circle-stroke-color": "#ffffff",
    
    // Blur properties
    "circle-blur": 0,
  },
});

Layout Property Examples

javascript
sdk.addLayer({
  id: "layout-layer",
  source: "source-id",
  type: "symbol",
  layout: {
    // Visibility
    visibility: "visible", // "visible" | "none"
    
    // Icon
    "icon-image": "icon-name",
    "icon-size": 1,
    "icon-rotate": 0,
    
    // Text
    "text-field": ["get", "name"],
    "text-font": ["Open Sans Semibold"],
    "text-size": 12,
    "text-anchor": "center",
  },
});

Data-driven Styles

javascript
// Set color based on property value
sdk.addLayer({
  id: "data-driven-layer",
  source: "source-id",
  type: "circle",
  paint: {
    "circle-color": [
      "case",
      ["==", ["get", "type"], "city"],
      "#ff0000",
      ["==", ["get", "type"], "airport"],
      "#0000ff",
      "#00ff00",
    ],
    "circle-radius": [
      "interpolate",
      ["linear"],
      ["get", "population"],
      0, 5,
      1000000, 20,
    ],
  },
});

Layer Order

Specify Insert Position

javascript
// Insert before specified layer
sdk.addLayer({
  id: "new-layer",
  source: "source-id",
  type: "circle",
}, "existing-layer-id"); // Before existing-layer-id

// Insert after specified layer
sdk.addLayer({
  id: "new-layer",
  source: "source-id",
  type: "circle",
}, "existing-layer-id", "after");

Using beforeId

javascript
sdk.addLayer({
  id: "new-layer",
  source: "source-id",
  type: "circle",
  beforeId: "existing-layer-id",
});

Updating Layers

Update Style

javascript
// Update paint property
sdk.setPaintProperty("layer-id", "circle-color", "#00ff00");

// Update layout property
sdk.setLayoutProperty("layer-id", "visibility", "none");

// Batch update
sdk.updateLayerStyle("layer-id", {
  paint: {
    "circle-color": "#00ff00",
    "circle-radius": 12,
  },
  layout: {
    visibility: "visible",
  },
});

Update Data

javascript
// Update GeoJSON source data
sdk.getSource("source-id").setData(newGeoJSON);

// Update Vector Tile source
sdk.getSource("source-id").setTiles([
  "https://new-url.com/tiles/{z}/{x}/{y}.pbf",
]);

Deleting Layers

Delete Layer

javascript
// Delete layer
sdk.removeLayer("layer-id");

// Use LayerManager
sdk.layerManager.removeLayer("layer-id");

Delete Source

javascript
// Delete source 
sdk.removeSource("source-id");

Layer Filtering

Using Filter

javascript
sdk.addLayer({
  id: "filtered-layer",
  source: "source-id",
  type: "circle",
  filter: [
    "all",
    [">=", ["get", "population"], 1000000],
    ["==", ["get", "type"], "city"],
  ],
  paint: {
    "circle-radius": 10,
    "circle-color": "#ff0000",
  },
});

Dynamic Filtering

javascript
// Update filter
sdk.setFilter("filtered-layer", [
  ">=",
  ["get", "population"],
  5000000,
]);

Complete Example

javascript
let sdk;

async function initMap() {
  sdk = new navMap.MapSDK({
    container: "map",
    center: [116.39, 39.9],
    zoom: 10,
  });

  sdk.on("loadComplete", () => {
    setupCustomLayers();
  });
}

function setupCustomLayers() {
  // 1. Add GeoJSON source
  sdk.addSource("custom-points", {
    type: "geojson",
    data: {
      type: "FeatureCollection",
      features: [
        {
          type: "Feature",
          geometry: {
            type: "Point",
            coordinates: [116.3974, 39.9093],
          },
          properties: {
            name: "Beijing",
            type: "city",
            population: 21540000,
          },
        },
        {
          type: "Feature",
          geometry: {
            type: "Point",
            coordinates: [121.4737, 31.2304],
          },
          properties: {
            name: "Shanghai",
            type: "city",
            population: 24870000,
          },
        },
      ],
    },
  });

  // 2. Add circle layer
  sdk.addLayer({
    id: "cities-circle",
    source: "custom-points",
    type: "circle",
    paint: {
      "circle-radius": [
        "interpolate",
        ["linear"],
        ["get", "population"],
        0, 5,
        10000000, 20,
        20000000, 30,
      ],
      "circle-color": [
        "case",
        [">=", ["get", "population"], 20000000],
        "#ff0000",
        [">=", ["get", "population"], 10000000],
        "#ff8800",
        "#00ff00",
      ],
      "circle-opacity": 0.8,
      "circle-stroke-width": 2,
      "circle-stroke-color": "#ffffff",
    },
  });

  // 3. Add label layer
  sdk.addLayer({
    id: "cities-label",
    source: "custom-points",
    type: "symbol",
    layout: {
      "text-field": ["get", "name"],
      "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
      "text-size": 12,
      "text-offset": [0, 1.5],
    },
    paint: {
      "text-color": "#000000",
      "text-halo-color": "#ffffff",
      "text-halo-width": 2,
    },
  });

  // 4. Add click event
  sdk.on("click", "cities-circle", (e) => {
    const feature = e.features[0];
    const popup = new navMap.Popup()
      .setLngLat(e.lngLat)
      .setHTML(`
        <h3>${feature.properties.name}</h3>
        <p>Population: ${feature.properties.population.toLocaleString()}</p>
      `)
      .addTo(sdk.map);
  });
}

initMap();

Notes

  1. Source Before Layer: Must add source first, then add layer
  2. Unique Layer ID: Each layer must have a unique ID
  3. Style Compatibility: Ensure style properties match layer type
  4. Performance Optimization: Consider using Vector Tiles or clustering for large amounts of data
  5. Memory Management: Unnecessary layers and sources should be deleted promptly