npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aapicoits/powermap-web-sdk

v1.0.1

Published

A professional-grade, high-performance Map SDK. Optimized for logistics, real-time tracking, indoor mapping, and 3D vehicle simulations.

Readme

PowerMap Web SDK 🚀

A professional-grade, high-performance Map SDK. Optimized for logistics, real-time tracking, indoor mapping, and 3D vehicle simulations.


2. 🏛️ Architecture Overview

The PowerMap Web SDK is built with a Layered Facade Architecture, ensuring that high-performance map rendering is wrapped in an easy-to-use, fluent JS API.

graph TD
    App[Web Application] --> PM[PowerMap Instance]
    
    subgraph "Facade Layer (Fluent API)"
        PM
    end

    subgraph "Manager Layer (Lazy Loading)"
        PM --> Registry[Component Registry]
        Registry --> MarkerMgr[MarkerManager]
        Registry --> SearchMgr[SearchManager]
        Registry --> RouteMgr[RoutingManager]
        Registry --> GeomMgr[GeometryManager]
        Registry --> EditorMgr[EditorManager]
        Registry --> LayerMgr[LayerManager]
    end

    subgraph "Service Layer"
        PM --> AuthMgr[AuthManager]
        PM --> Events[EventBus]
        AuthMgr --> Cache[Token Cache]
    end

    subgraph "Visual Engine"
        PM --> ML[PowerMap Visual Engine]
    end

    Cache -.-> Storage[(Local Storage)]
    AuthMgr -.-> API((PowerMap APIs))

3. 📦 Installation

Install the package via npm or yarn:

npm install @powermap/web-sdk

4. 🚀 Quick Start

Get a map up and running in less than 2 minutes. The PowerMap SDK is designed for chaining and ease of use.

Step A: Prepare your HTML

<div id="map" style="width: 100%; height: 500px; border-radius: 8px; overflow: hidden;"></div>

Step B: Initialize and Style

import { PowerMap } from "@powermap/web-sdk";

// 1. Initialize with dual-auth system
const map = new PowerMap({
  container: "map",
  center: [100.5018, 13.7563], // Bangkok [Longitude, Latitude]
  zoom: 14,
  mapApiKey: "YOUR_MAP_API_KEY", // Public key for tiles and base layers
  auth: {
    clientId: "YOUR_CLIENT_ID",     // Service Credentials for backend APIs
    clientSecret: "YOUR_CLIENT_SECRET"
  },
  previewOnly: true // Optional: Lock all user interactions (Static View)
});

// 2. Chaining for smooth DX
map.onMapLoaded((e) => {
  console.log("PowerMap is ready!", e.map);
  
  // Add a marker as soon as the map loads
  map.addMarker({
    position: [100.5018, 13.7563],
    type: "start",
    popupContent: "<strong>Origin Point</strong>"
  });
})
.setStyle('th') // Options: 'th', 'en', 'dark', 'gray'
.flyTo({ zoom: 16, pitch: 45 });

[!TIP] Performance Note: The PowerMap Web SDK uses a lazy-loading registry pattern. Managers (Routing, Search, etc.) are only initialized once you first call them, keeping your app's initial memory footprint minimal.


5. 🔗 Method Chaining

The PowerMap SDK is built with a fluent interface, allowing you to link multiple configuration steps and event listeners together in a single statement.

Supported Methods

Most methods that perform an action on the map (styling, camera movement, or event registration) return the PowerMap instance to facilitate chaining.

| Group | Chainable Methods | | :--- | :--- | | Events | on, off, onMapLoaded, onClick, onMapLongClick, onMarkerClick, onPoiClick, onMarkerDrag, onMarkerDragEnd, onRouteCalculated, onError | | Camera | flyTo, easeTo, fitBounds, jumpTo, setPitch, setBearing, zoomIn, zoomOut, rotateLeft, rotateRight | | Map Style | setStyle | | Markers | removeMarker, updatePopup, clearMarkers | | Search | search | | Routing | clearRoutes | | Layers | showLayer, hideLayer, toggleLayer |

[!NOTE] Methods that return a Promise (like addRoute) or a new Object (like addMarker or getRouteDetails) interrupt the chain.

Chaining Example

map.onMapLoaded(() => console.log("Ready!"))
  .onMarkerClick(data => console.log("Clicked:", data))
  .setStyle('dark')
  .flyTo({ center: [100.5, 13.7], zoom: 12 })
  .setPitch(45);

6. 🛠️ Configuration Reference

When creating a new PowerMap(options), the following options are available:

| Option | Type | Default | Required | Description | | :--- | :--- | :--- | :--- | :--- | | container | string | - | Yes | The HTML element ID where the map will be rendered. | | mapApiKey | string | - | Yes | Your PowerMap Public API Key for map tiles. | | auth | Object | - | Yes | Service Credentials. Used for connecting to backend APIs of PowerMap services (e.g., Routing, Optimization). Contains clientId and clientSecret. | | center | [lng, lat] | [100, 13] | No | The initial center point of the map. | | zoom | number | 14 | No | Total zoom level (0-22). | | baseUrl | string | - | No | Optional proxy URL (e.g., /api/proxy). If set, the SDK will route all API requests through this URL. | | maptilerKey | string | - | No | Your MapTiler API Key. Required if you intend to use high-resolution satellite layers. | | previewOnly | boolean | false | No | If true, the map will be non-interactive (no zoom, pan, rotate, or pitch). Perfect for static map previews. |

Core Instance Methods

These methods are available on the PowerMap instance to manage the map state and lifecycle.

| Method | Arguments | Description | | :--- | :--- | :--- | | on(event, cb) | string, function | Subscribe to any map event (see Section 9). | | off(event, cb) | string, function | Unsubscribe from a previously registered event. | | setMode(mode, opts) | string, Object | Switch between 'standard' and 'indoor' modes. | | setStyle(name) | string | Change the map style (e.g., 'th', 'dark'). | | setNavigationControl(opts) | boolean\|Object | Enable/disable or customize zoom/compass controls. | | setFullscreenControl(opts) | boolean\|Object | Enable/disable fullscreen control. | | debug() | - | Access the Debug Manager for telemetry and performance tools. | | onError(callback) | function | Global error listener for Auth, Map, or Routing issues. |


7. 📍 Marker Management

Our marker system simplifies standard map markers with built-in presets for logistics and easy event handling.

addMarker(options) Options

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | position | [lng, lat] | Required | Coordinates for the marker. | | type | string | 'default' | Preset icons: 'start', 'destination', 'waypoint'. | | iconUrl | string | - | Custom image URL to use as the icon. Overrides type. | | width/height | string | '30px'/'38px' | CSS dimensions for the marker icon. | | anchor | string | 'bottom' | Where the marker is anchored to the coordinate. | | draggable | boolean | false | If true, user can drag the marker. Fires onMarkerDrag events. | | rotation | number | 0 | Icon rotation in degrees. | | popupContent | string|Object | - | HTML string or Structured Object to display in a premium popup. | | id | string | - | Unique ID to track this marker. Allows retrieval via getMarker(id). | | color | string | - | Custom hex color for pinpoint marker (e.g. '#ff4444'). Uses High-Accuracy GL Rendering. | | icon | string | - | FontAwesome icon class for pinpoint marker (e.g. 'fas fa-car'). | | element | HTMLElement | - | Use a raw HTML element as a fully custom marker. |

[!IMPORTANT] High-Accuracy Rendering: Markers with a color property use our new GL Symbol Layer system. These markers are rendered directly on the map canvas, ensuring perfect alignment and zero-lag during zoom or pan. Ordinary preset markers (type) use standard DOM elements for maximum compatibility.

Marker Examples

Standard Presets

map.addMarker({
  position: [100.5, 13.7],
  type: 'start', // 'start', 'destination', 'waypoint'
  popupContent: "Start Point"
});

Premium Colored Markers (No Image Required)

map.addMarker({
  position: [100.52, 13.78],
  color: '#f97316',      // Vibrant Orange
  icon: 'fas fa-store',  // FontAwesome Icon
  draggable: true,      // Enable high-accuracy dragging
  popupContent: {
    title: "Power Shop",
    tag: "Retail",
    body: "Custom colored marker with icon."
  }
});

Draggable Markers & Events

You can enable dragging for any marker. For GL-rendered markers (those with color), dragging is handled with sub-pixel precision.

const marker = map.addMarker({
  position: [100.5, 13.7],
  color: '#3b82f6',
  draggable: true
});

// 1. Listen via Proxy (Recommended)
marker.on('drag', (e) => console.log('Current:', e.lngLat));
marker.on('dragend', (e) => console.log('Final:', e.lngLat));

// 2. Listen via Global Event Bus
map.onMarkerDrag(({ marker, lngLat }) => {
  console.log(`Marker is moving to: ${lngLat.lng}, ${lngLat.lat}`);
});

Structured Popup Content & Actions

Instead of raw HTML, you can pass a structured object to popupContent for a premium, consistent look. You can also define interactive buttons using the action or actions property:

map.addMarker({
  position: [100.5, 13.7],
  popupContent: {
    title: "Siam Paragon",
    tag: "Mall",
    body: "The pride of Bangkok with world-class shopping.",
    footer: "Open: 10:00 - 22:00",
    actions: [
      { label: "View Details", url: "https://example.com/details", target: "_blank" },
      { label: "Navigate Here", url: "https://example.com/nav", color: "#10b981" }
    ]
  }
});

Marker Methods

| Method | Arguments | Description | | :--- | :--- | :--- | | addMarker(options) | Object | Create and add a marker. Returns marker instance. | | getMarker(id) | string | Retrieve a marker instance by its unique ID. | | removeMarker(markerOrId) | Object\|string | Remove a marker using instance or ID. | | updatePopup(marker, content) | Object, string\|Object | Update the popup content (HTML or Structured Object). | | clearMarkers() | - | Remove all markers from the map. |


8. 🎨 CSS Customization

The PowerMap SDK automatically wraps all map elements in a global .powermap-sdk class and provides branded aliases for all internal UI components.

The Global Wrapper

Any HTML element you provide as a container will automatically have the powermap-sdk class applied at runtime. This provides a clean scope for all PowerMap styles.

<!-- Input -->
<div id="map"></div>

<!-- Output at runtime -->
<div id="map" class="powermap-sdk">...</div>

Premium Class Aliases

To make customization even more intuitive, we've provided branded CSS classes that you can target directly:

| Feature | PowerMap Class | Description | | :--- | :--- | :--- | | Marker | .pm-marker | The main container for any marker. | | Popup | .pm-popup | The root container of a popup. | | Popup Content | .pm-popup-content | The main content area (glassmorphism). | | Popup Header | .pm-popup-header | The header (part of structured content). | | Popup Body | .pm-popup-body | The body text area. | | Popup Tag | .pm-popup-tag | The category tag. | | Popup Footer | .pm-popup-footer | The bottom meta info area. | | Popup Close | .pm-popup-close | The close button element. | | Popup Tip | .pm-popup-tip | The triangular tip pointing to the marker. | | Nav Group | .pm-ctrl-group | The container of zoom/compass buttons. | | Zoom In | .pm-ctrl-zoom-in | The zoom in button. | | Zoom Out | .pm-ctrl-zoom-out | The zoom out button. | | Compass | .pm-ctrl-compass | The compass/rotation button. |

Premium Overrides

Target your own CSS using the scoped wrapper or branded aliases:

/* Change the header color of structured popups */
.powermap-sdk .pm-popup-header {
  background: linear-gradient(135deg, #000 0%, #333 100%);
}

/* Customize the glassmorphism background of all popups */
.powermap-sdk .pm-popup-content {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
}

/* Custom Marker Scale */
.powermap-sdk .pm-marker {
  transform: scale(1.1);
}

setNavigationControl(options) Options

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | position | string | 'top-right' | Position on the map: 'top-left', 'top-right', 'bottom-left', 'bottom-right'. | | showZoom | boolean | true | If true, display the zoom in and zoom out buttons. | | showCompass | boolean | true | If true, display the compass (rotation) button. | | visualizePitch | boolean | true | If true, the compass button will rotate on the Y-axis to visualize map pitch (3D view). |

Map Control Examples

// Simple: Enable default branded controls (top-right)
map.setNavigationControl(true);

// Advanced: Custom position and visibility
map.setNavigationControl({
  position: 'bottom-right',
  showZoom: true,
  showCompass: false
});

// Disable controls
map.setNavigationControl(false);

9. 🛣️ Routing & Optimization

Generate high-precision routes with automatic visualization. The SDK automatically fits the map view to the resulting route.

addRoute(options) Options

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | start | [lng, lat] | Required | Start point coordinates. | | destination | [lng, lat] | Required | End point coordinates. | | waypoints | Array<[lng, lat]> | [] | List of points to hit between start and end. | | optimize | boolean | false | If true, reorders waypoints to find the shortest total trip (TSP). Requires at least 1 waypoint. | | profile | string | 'driving' | Routing engine profile: 'driving', 'walking', 'cycling'. | | language | string | 'th' | Return instructions/names in 'th' or 'en'. | | routeColor | string | '#3b82f6' | Hex color code for the main route line. | | routeWidth | number | 5 | Thickness of the main route line. | | routeOpacity | number | 1.0 | Opacity of the route line (0.0 to 1.0). | | casingColor | string | '#1d4ed8' | Hex color for the route's outer border (shadow). | | casingWidth | number | 8 | Thickness of the casing line. |

Route Methods

| Method | Arguments | Description | | :--- | :--- | :--- | | addRoute(options) | Object | Calculate, draw route and fit view. Returns Promise. | | clearRoutes() | - | Remove all route lines and markers from map. | | getRouteDetails() | - | Returns distance, duration, and formatted strings. | | getRouteSummary() | - | Returns top-level distance/duration strings. |

addRoute(options) Return Object

The addRoute method returns a Promise that resolves to a RouteResult object containing:

| Property | Type | Description | | :--- | :--- | :--- | | distance | number | Total distance of the route in meters. | | duration | number | Estimated travel time in seconds. | | steps | Array<Object> | Turn-by-turn instructions (text, distance, duration, location). | | geometry | Object | GeoJSON LineString of the route. | | raw | Object | Raw response from the PowerMap routing backend. |

steps Object Structure

Each step in the steps array represents a turn or maneuver:

| Field | Type | Description | | :--- | :--- | :--- | | text | string | The maneuver instruction (e.g., "เลี้ยวขวาที่ถนนสุขุมวิท"). | | distance | number | Distance to travel for this step (meters). | | duration | number | Estimated time for this step (seconds). | | location | [lng, lat] | Geographic coordinate where the maneuver starts. |

Routing Example

// Simple route from A to B
const route = await map.addRoute({
  start: [100.5018, 13.7563],
  destination: [100.5118, 13.7663],
  language: "en"
});

// Complex optimized route with waypoints
const optimizedRoute = await map.addRoute({
  start: [100.50, 13.75],
  destination: [100.60, 13.85],
  waypoints: [
    [100.55, 13.80],
    [100.52, 13.78]
  ],
  optimize: true, // Will reorder the 2 waypoints for the best efficiency
  language: "th"
});

console.log(`Total Distance: ${optimizedRoute.distance}m`);
console.log(`Total Duration: ${optimizedRoute.duration}s`);

// Custom red route for heavy traffic visualization
const redRoute = await map.addRoute({
  start: [100.5, 13.7],
  destination: [100.6, 13.8],
  routeColor: "#ff0000",
  routeWidth: 10,
  casingColor: "#990000"
});

// Clear all routes from visibility
map.clearRoutes();

📍 Route Summary Helpers

Quickly access formatted summaries (distance in km/m, time in hours/mins) for the total route and individual steps:

// Get enhanced details (Recommended)
const details = map.getRouteDetails();
if (details) {
    console.log(`Total: ${details.distanceStr}, Time: ${details.durationStr}`);
    
    // Each step also contains formatted strings
    details.steps.forEach(step => {
        console.log(`${step.text} (${step.distanceStr})`);
    });
}

// Get just the top-level summary
const summary = map.getRouteSummary(); // { distanceStr, durationStr }

🏗️ 10. Map Layers Management

The LayerManager provides a robust API to toggle built-in map layers (e.g., Roads, Railways, BTS/MRT, City Plans) on and off. The SDK dynamically fetches these layers from the catalog and applies them to your current map style.

Built-in Layer Groups

Map layers are grouped into 3 main categories:

  1. CITY PLAN (city): City plans for various provinces.
  2. TRANSPORT (transport): Roads, Current/Future Railways, Current/Future BTS/MRT.
  3. INSIGHT DATA (insight): Night lights, Satellite imagery.

Layer APIs

| Method | Arguments | Description | | :--- | :--- | :--- | | map.layers.getCatalog() | - | Returns the full list of available layer groups and IDs. | | map.layers.ensure(layerId) | string | Ensures a layer's sources are created (idempotent). | | map.layers.show(layerId) | string | Ensures and shows a specific layer. | | map.layers.hide(layerId) | string | Hides a specific layer. | | map.layers.toggle(layerId) | string | Toggles the visibility of a layer. | | map.layers.getLayerState(id) | string | Returns {loaded, visible} status. | | map.layers.setOpacity(id, val) | string, number | Adjusts the transparency (0.0 - 1.0). | | map.layers.showGroup(key) | string | Shows all layers within a specific group. | | map.layers.hideGroup(key) | string | Hides all layers within a specific group. | | map.layers.hideAll() | - | Hides every active layer from the catalog. |

Usage Example

map.onMapLoaded(async () => {
  // 1. View all available layers
  const catalog = map.layers.getCatalog();
  console.log(catalog);

  // 2. Show the Road layer
  await map.layers.show('pm-road-vt');

  // 3. Toggle the current Railway layer
  await map.layers.toggle('pm-current-railway-th-vt');

  // 4. Adjust opacity
  map.layers.setOpacity('pm-road-vt', 0.5);

  // 5. Hide an entire group
  map.layers.hideGroup('city');
});

You can also use convenience methods directly on the PowerMap instance:

await map.showLayer('pm-road-vt');
map.hideLayer('pm-road-vt');
await map.toggleLayer('pm-road-vt');

[!IMPORTANT] Satellite Layer: High-resolution satellite imagery (pm-maptiler-satellite-layer) requires a maptilerKey provided in the initial PowerMap configuration.


11. 🎥 Camera & Viewport Control

Take full control of the user's perspective with smooth transitions or direct manipulation.

Movement Functions

| Method | Arguments | Description | | :--- | :--- | :--- | | flyTo(options) | Object | Smooth cinematic movement with options: center, zoom, pitch, bearing, duration. | | easeTo(options) | Object | Linear transition movement. Same options as flyTo. | | jumpTo(options) | Object | Instant teleportation without animation. | | fitBounds(bounds, opts) | Array, Object | Fits view to show all coords. Options: padding. | | zoomIn() | - | Smoothly zoom in by level 1. | | zoomOut() | - | Smoothly zoom out by level 1. | | rotateLeft() | - | Smoothly rotate left by 45 degrees. | | rotateRight() | - | Smoothly rotate right by 45 degrees. |

State Functions

| Method | Arguments | Description | | :--- | :--- | :--- | | setPitch(deg, anim) | number, bool | Set tilt angle (0-85). Smooth by default. | | setBearing(deg, anim) | number, bool | Set direction (0-360). Smooth by default. | | getCenter() | - | Returns {lng, lat} of the current map center. | | getZoom() | - | Returns the current zoom level as a number. | | getPitch() | - | Returns the current pitch (tilt) as a number. | | getBearing() | - | Returns the current bearing (rotation) as a number. |

Camera Examples

// Fly into a specific warehouse view
map.flyTo({
  center: [100.5, 13.8],
  zoom: 17,
  pitch: 60,
  bearing: 45,
  duration: 4000
});

// Fit view to a specific region
map.fitBounds([
  [100.4, 13.7], 
  [100.6, 13.9]
], { padding: 40 });

11. 🔥 Event System

The SDK uses a semantic event system for a modern developer experience. All events can be chained.

Event List & Arguments

| Method | Callback Arguments | Triggered When... | | :--- | :--- | :--- | | onMapLoaded | {map} | The map is fully initialized and layers can be added. | | onClick | {lngLat, point, ...} | The map is clicked. | | onMapLongClick | {lngLat, point, ...} | The map is long-pressed or right-clicked. | | onMarkerClick | {marker, originalEvent, options} | A user clicks on any marker added via SDK. | | onPoiClick | {feature, lngLat, point} | A user clicks on a Point of Interest (POI) on the base map. | | onModeChanged | {mode, options} | The SDK operational mode (standard/indoor) has changed. | | onMarkerDrag | {marker, lngLat, options} | A draggable marker is currently being moved. | | onMarkerDragEnd | {marker, lngLat, options} | A user releases a draggable marker. | | onRouteCalculated | route | A new route has been fetched and drawn. | | onGeometryExported | {data} | GeoJSON data has been exported from the editor. | | layerEnsured | {layerId, group} | A catalog layer has finished initializing sources. | | onError | {source, message} | Any internal error (Auth, Routing, Map) occurs. |

Event Subscription Example

map.onMapLoaded((e) => {
  console.log("Ready!");
})
.onClick((e) => {
  console.log(`Map clicked at: ${e.lngLat}`);
})
.onMarkerClick((data) => {
  alert(`You clicked marker: ${data.options.popupContent}`);
})
.onMarkerDragEnd((data) => {
  console.log(`New Coordinate: ${data.lngLat.lng}, ${data.lngLat.lat}`);
});

12. 🔍 Search & Geocoding

The Web SDK provides built-in search capabilities using the PowerMap Search API.

search(query, options)

Available options:

  • lang: 'th' (default) or 'en'.
  • location: [latitude, longitude] to prioritize nearby results.
const results = await map.search("Central World", { lang: 'en' });

results.forEach(item => {
  console.log(`${item.name}: ${item.address}`);
  console.log(`Position: ${item.position}`); // [lat, lng]
});

13. 🕹️ Interactive Metadata (POI)

The SDK can detect when a user clicks on a Point of Interest (POI) on the base map (e.g., shopping malls, parks, gas stations).

map.onPoiClick(({ feature, lngLat }) => {
  const name = feature.properties.name_t;
  console.log(`User clicked on: ${name}`);
  
  // Highlighting the POI with a popup
  map.addMarker({
    id: 'poi-temp',
    position: [lngLat.lng, lngLat.lat],
    popupContent: { title: name, tag: 'POI' }
  });
});

14. 🧰 Utility Functions

SDK provides handy formatters for displaying routing data.

| Method | Arguments | Description | | :--- | :--- | :--- | | formatDistance(meters) | number | Converts meters to string (e.g., "1.25 km" or "500 m"). | | formatDuration(seconds) | number | Converts seconds to string (e.g., "1h 30m" or "5 min"). |


15. 📐 Geometry Engine & Editor

The PowerMap SDK includes a professional-grade geometry engine and a built-in UI for creating, editing, and managing spatial data. This is optimized for both simple outdoor measuring and complex indoor mapping.

15.1 The Editor Toolbar

Enable a premium, built-in toolbar that handles the entire drawing lifecycle.

map.editor.enable({
  position: 'bottom-left', // 'top-left', 'top-right', 'bottom-left', 'bottom-right'
  mode: 'standard'         // 'standard' (Logistics) or 'indoor' (Indoor Mapping)
});

Interactive Tools

  • Standard Mode: Point, Line (Measure), Polygon (Area), Rectangle.
  • Indoor Mode: Beacon, POI, Walkway, Floor, Obstacle.

15.2 Measurement & Info Panel

When a feature is selected, a real-time measurement panel appears, providing:

  • Distance: For lines and walkways.
  • Area: For polygons and floors.
  • 3D Height: For extruded features.
  • Live Coordinates: For Points (POIs and Beacons), showing relative X/Y metrics dynamically during placement inside buildings, or Latitude/Longitude for outdoor placements.

15.3 Property Editor UI

The PowerMap Editor includes a functional Property Editor panel (available in indoor mode or via the settings icon). It allows you to manage:

  • Core Metadata: ID and Name.
  • Classification: Independent feature_type (e.g., level, building, venue), explicit Categories, and Ordinal/Level (for stacking floors).
  • Visual Styling: Choose colors and icons (for Beacons and POIs).
  • Custom Properties: Add unlimited key-value pairs for your own business logic.

15.4 3D & Advanced Tools

Take drawing to the next dimension:

  • Extrude: Transform 2D polygons into 3D buildings or obstacles by setting the height property.
  • Rotate & Clone: Rapidly duplicate and align features.
  • Vertical Alignment: Manage ordinal properties to ensure data belongs to the correct floor level.

15.5 Data Lifecycle (Import/Export)

The Editor facilitates easy data exchange via GeoJSON:

  • Export: Built-in "Download" button in the toolbar, or call map.geometry.export().
  • Import: Built-in "Upload" button, or call map.geometry.import(geojson).
  • IMDF Compliance: Indoor fields (feature_type, category, ordinal) are mapped to IMDF format automatically.

15.6 Unified Programmatic CRUD API

For the full reference, see GEOMETRY.md

All operations — whether from draw tool or code — emit the same geometryChanged event.

// CREATE (standard)
const id = map.geometry.create('polygon', {
  coordinates: [[[100.5,13.7],[100.6,13.7],[100.6,13.8],[100.5,13.7]]],
  properties: { fillColor: '#4f46e5', height: 10 }
});

// CREATE (indoor)
const beaconId = map.geometry.create('beacon', {
  lngLat: [100.52, 13.75],
  properties: { ordinal: 1, name: 'BKK-01' }
});

// READ
map.geometry.getById(id);                          // Feature | null
map.geometry.getByKind('beacon');                  // Feature[]
map.geometry.query().byKind('poi').byFloor(1).toArray();  // Feature[]

// UPDATE
map.geometry.update(id, {
  properties: { name: 'Updated Name', color: '#ff0000' }
});

// DELETE
map.geometry.remove(id);
map.geometry.clear();

All CRUD Methods:

| Method | Arguments | Description | | :--- | :--- | :--- | | create(kind, options) | string, Object | Create a standard or indoor feature programmatically | | update(id, patch) | string, Object | Update properties and/or geometry of an existing feature | | getById(id) | string | Returns a single GeoJSON Feature or null | | getByKind(kind) | string | Returns all indoor features matching the given kind | | query() | - | Returns a chainable GeometryQuery builder | | add(geojson) | Object | Manually add a raw GeoJSON feature (legacy) | | remove(id) | string\|string[] | Remove one or multiple features by ID | | clear() | - | Remove all geometry from the map | | setFeatureHeight(id, m) | string, number | Extrude a polygon into a 3D volume | | getGeoJSON(id?, opts) | string, Object | Returns feature(s) as GeoJSON (options.format: 'imdf' \| 'standard') | | export(opts) | Object | Returns all features as GeoJSON | | import(geojson, opts) | Object, Object | Loads GeoJSON/IMDF data |

15.7 GeometryStore — Placeholder API Bridge

map.geometry.store provides placeholder hooks that fire on every geometry change regardless of origin (draw tool or code). Use this to connect your own backend API.

// Register before the map loads
map.geometry.store.onCreate(async (payload) => {
  console.log('[Placeholder] CREATE', payload);
  // await fetch('/api/features', { method: 'POST', body: JSON.stringify(payload) })
});
map.geometry.store.onUpdate(async (payload) => {
  console.log('[Placeholder] UPDATE', payload);
  // await fetch(`/api/features/${payload.featureId}`, { method: 'PUT', body: JSON.stringify(payload) })
});
map.geometry.store.onDelete(async (payload) => {
  console.log('[Placeholder] DELETE', payload);
  // await fetch(`/api/features/${payload.featureId}`, { method: 'DELETE' })
});

// Used when a developer clicks the "Save" icon on the draw toolbar
map.geometry.store.onSave(async (data) => {
  console.log('[Placeholder] MANUAL SAVE TRIGGERED', data);
  // const success = await saveAllToDatabase(data);
  // if (success) map.geometry.store.setDirty(false); // Clear unsaved warnings
});

Each callback receives a clean payload with user_ prefixes stripped:

{
  operation:  'create' | 'update' | 'delete',
  source:     'draw' | 'programmatic',
  format:     'standard' | 'indoor',
  featureId:  'abc123',
  kind:       'beacon' | 'poi' | ... | null,   // null for standard
  floor:      1 | null,                         // ordinal, null for standard
  timestamp:  '2026-03-27T...',
  geometry:   { type: 'Point', coordinates: [...] },
  properties: { name: 'BKK-01', color: '#fbbf24' }
}

[!NOTE] If no callback is registered, the SDK logs all events to the console automatically with 📦 CREATE / ✏️ UPDATE / 🗑️ DELETE icons.

15.8 SDK Events

// Subscribe to every geometry change (create/update/delete)
map.on('geometryChanged', ({ operation, source, feature }) => {
  // operation: 'create' | 'update' | 'delete'
  // source:    'draw' | 'programmatic'
  // feature:   GeoJSON Feature (null for delete)
});

// Subscribe to live coordinate/property updates from the UI Editor
// Use this to refresh UI panels instantly without waiting for or triggering a backend save.
map.on('geometryLiveUpdate', ({ type, features }) => {
  // type: 'update'
  // features: Array of GeoJSON Features that are currently being edited
});

// Listen to selection changes
map.on('geometrySelectionChanged', ({ features }) => {
  // Array of currently selected feature objects
});

16. 🏠 Indoor Mapping

The PowerMap SDK provides a robust API for managing indoor environments, including floor switching, category filtering, and specialized geometry handling.

16.1 Enabling Indoor Mode

Switch to indoor mode to enable building-specific logic and specialized drawing tools (e.g., Beacons, Walkways).

map.setMode('indoor');

16.2 Floor Management (map.indoor)

When in indoor mode, use the map.indoor facade to control the vertical context of the map.

| Method | Arguments | Description | | :--- | :--- | :--- | | setFloor(ordinal, opts) | number, Object | Switch to a specific floor level (e.g., 1, 2, -1). | | getAvailableFloors() | - | Returns a sorted array of all unique floor ordinals found in the map data. | | getCurrentFloor() | - | Returns the ordinal of the currently active floor. |

Switching Floors with Animation

// Switch to Floor 2 with a smooth fade transition
map.indoor.setFloor(2, { animate: true });

Building a Dynamic Floor Selector UI

// Get all available floors to populate a dropdown
const floors = map.indoor.getAvailableFloors(); 
// Returns: [1, 2, 3] or [] if no indoor data is found

16.3 Visibility Control

Toggle the visibility of specific indoor data categories. These settings persist across floor changes.

// Toggle individual categories
map.indoor.setCategoryVisible('poi', true);       // Points of Interest
map.indoor.setCategoryVisible('beacon', false);   // Beacons/Sensors
map.indoor.setCategoryVisible('walkway', true);   // Navigation Paths
map.indoor.setCategoryVisible('obstacle', true);  // 3D Obstacles/Buildings

16.4 Indoor Data Kinds

The SDK categorizes indoor features using the user_kind (or kind) property:

  • floor: The walkable surface area of a floor (Polygon).
  • obstacle: Non-walkable areas. Can be extruded into 3D.
  • walkway: Navigable path lines for indoor routing.
  • poi: Indoor points of interest with custom icons.
  • beacon: Positioning hardware or logical points.

16.5 Event Synchronization

// Listen for mode changes
map.on('onModeChanged', ({ mode }) => {
  console.log(`Mode switched to: ${mode}`); // 'standard' or 'indoor'
});

// Sync UI when data is added/deleted or imported
map.on('geometryChanged', () => {
   const updatedFloors = map.indoor.getAvailableFloors();
   // Refresh your floor selector here
});

17. ⌨️ Keyboard Shortcuts

The SDK provides built-in productivity shortcuts whenever the geometry engine is active:

  • Ctrl + C: Copy selected geometry.
  • Ctrl + V: Paste geometry at the current cursor position.
  • Delete / Backspace: Remove selected features.

18. 🩺 Debug & Telemetry

Enable the Debug HUD during development to monitor performance and coordinates.

// Enable debug panel
map.debug().enable({ position: 'top-right' });

// Toggle specific metrics
map.debug().showFPS(true);
map.debug().showCoordinate(false);

// Disable
map.debug().disable();

19. 🛠 Build & Development

For contributors to the SDK core:

Contributor Guide

  1. Setup Environment:

    npm install
  2. Local Development:

    npm run dev
  3. Production Build:

    npm run build

Project Structure

  • /src/core: Map lifecycle and shared managers.
  • /src/geometry: Drawing engine and coordinate logic.
  • /src/editor: Toolbar UI and control components.
  • /src/routing: Navigation and path-finding.
  • /src/auth: Security and API tokens.

📌 Appendix A: Complete SDK Event List

The SDK emits the following events through its central EventBus. You can subscribe to them via map.on(eventName, callback).

🌍 Core / Global

| Event | Payload | Description | |---|---|---| | mapLoaded | { map } | Fired when PowerMap finishes loading the style and is ready. | | mapStyleChanged | { styleKey } | Fired after switching the base map style. | | modeChanged | { mode, options } | Fired when SDK interactive mode changes (e.g. mode_freemode_routing). | | error | PowerMapError | Fired globally for SDK internal errors. |

📐 Geometry & Draw

| Event | Payload | Description | |---|---|---| | geometryChanged | { operation/type, source, feature(s) } | Fired upon completion of a CRUD operation or drawing action. | | geometryLiveUpdate | { type: 'update', features } | Fired rapidly during property/coordinate editing for real-time UI mapping. | | geometrySelectionChanged | { features } | Fired when the active selection changes in drawing mode. |

📍 Markers

| Event | Payload | Description | |---|---|---| | markerAdded | { marker, options } | Fired when a new marker is added to the map. | | markerRemoved | { marker\|id } | Fired when a marker is explicitly removed. | | markerClick | { marker, originalEvent, options } | Fired when a marker is clicked. | | markerDrag | { marker, lngLat, options } | Fired continuously while a draggable marker is being dragged. | | markerDragEnd | { marker, lngLat, options } | Fired when a marker is dropped after dragging. | | markersCleared| - | Fired when all markers on the map are cleared. |

🏢 Indoor

| Event | Payload | Description | |---|---|---| | floorChanged | ordinal (number) | Fired when the active indoor floor changes. |

🗺️ Routing & Navigation

| Event | Payload | Description | |---|---|---| | routeRequestStart| options | Fired when a route calculation request is initiated. | | routeCalculated | GeoJSON Feature | Fired upon successful calculation of a MultiLineString route. | | routeCleared | - | Fired when the active route is removed from the map. | | navigationStart | - | Fired when Turn-by-Turn navigation is initiated. | | navigationEnd | - | Fired when Turn-by-Turn navigation stops. | | simulationStart | - | Fired when GPS Route Simulator starts running. | | simulationUpdate| { position, step } | Fired at every tick of the GPS simulator with the interpolated position. | | simulationEnd | - | Fired when GPS simulation halts or reaches the destination. |

🎨 Layers

| Event | Payload | Description | |---|---|---| | layerVisibilityChanged| { layerId, visible } | Fired when a system layer's visibility is toggled. | | layerEnsured | { layerId, group } | Fired when the SDK auto-creates a missing required layer group. |


© 2026 PowerMap Development Team. All rights reserved.