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

@sovereignsolutions/ss-map-gl

v1.0.10

Published

This SDK provides high-performance vector drawing (polygons, circles, text notations), GeoJSON serialization, and spatial clustering on top of MapLibre GL.

Readme

Map SDK Integration & Developer Guide

This SDK provides high-performance vector drawing (polygons, circles, text notations), GeoJSON serialization, and spatial clustering on top of MapLibre GL.


🚀 Installation & Setup

1. Install via NPM

Install the package from the npm registry:

npm install @sovereignsolutions/ss-map-gl

2. Usage in Bundlers (ESM / TypeScript / React / Vue)

Import the library components and standard CSS stylesheet:

import { MapEngine, DrawingController, ClusterController } from '@sovereignsolutions/ss-map-gl';
import '@sovereignsolutions/ss-map-gl/dist/ss-map-gl.css';

3. Usage via CDN (HTML / UMD)

Include the bundled assets directly from CDN in your HTML files:

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@sovereignsolutions/ss-map-gl/dist/ss-map-gl.css">
  <style>#map { width: 100vw; height: 100vh; }</style>
</head>
<body>
  <div id="map"></div>

  <script src="https://cdn.jsdelivr.net/npm/@sovereignsolutions/ss-map-gl/dist/ss-map-gl.umd.js"></script>
  <script>
    // Access variables under the global SSMapGL namespace
    const mapEngine = new SSMapGL.MapEngine({
      container: 'map',
      center: [78.9629, 20.5937],
      zoom: 5
    });

    const drawController = new SSMapGL.DrawingController(mapEngine);
  </script>
</body>
</html>

🛠️ Local Development (Showcase App)

To run the developer showcase locally:

# Install dependencies
npm install

# Start Vite dev server locally at http://localhost:5173/
npm run dev

# Compile TypeScript and bundle production builds
npm run build

💻 SDK API Examples

1. Map Initialization & Styles

Initialize the map engine with optional style source and API key configuration:

import { MapEngine } from '@sovereignsolutions/ss-map-gl';

// A. Standard Basic style (Default)
const mapEngine = new MapEngine({
  container: 'map',
  center: [78.9629, 20.5937],
  zoom: 5
});

// B. Premium sovereign style using Predefined Style name and API key
const premiumMap = new MapEngine({
  container: 'map',
  style: 'DARK', // Choose one of the predefined styles
  apiKey: 'your_sovereign_api_key', // Required for premium styles
  center: [78.9629, 20.5937],
  zoom: 5
});

Predefined Premium Styles

The SDK integrates directly with Sovereign's premium vector tile server. The following predefined style identifiers can be supplied to the style configuration:

  • 3D
  • BASIC
  • BRIGHT
  • DARK
  • FIORD
  • LIBERTY
  • POSITRON
  • TERRAIN
  • TONER

Dynamic Style Switching

Change base map styles dynamically on the fly. Active cluster layers and drawing canvases will automatically reload themselves without losing visual data or throwing console warnings:

// Switch style dynamically
mapEngine.setStyle('BASIC', 'your_sovereign_api_key');

2. Vector Drawing Control (Polygons, Circles & Text Notations)

Instantiate drawing tools and bind active modes:

import { DrawingController } from '@sovereignsolutions/ss-map-gl';

const drawingController = new DrawingController(mapEngine, {
  showToolbar: true, // Display the premium floating toolbar on map
  onDrawComplete: (features) => console.log('Drawing finished:', features),
  onShapeSelect: (features) => console.log('Selected:', features),
  onShapeUpdate: (features) => console.log('Updated:', features),
  onShapeDelete: (features) => console.log('Deleted:', features),
});

// Set drawing mode programmatically
drawingController.setMode('polygon');   // Enter Polygon Drawing mode
drawingController.setMode('circle');    // Enter Circle Drawing mode
drawingController.setMode('notation'); // Enter Text Notation mode
drawingController.setMode('select');   // Enter Select/Edit mode
drawingController.setMode('trash');    // Delete currently selected feature(s)

Drawing Modes

| Mode | Description | |:-----|:------------| | 'polygon' | Click to place vertices, double-click to close the shape | | 'circle' | Click to set center, drag to define radius | | 'notation' | Click on the map to place a text label anchor point | | 'select' | Select, move, and edit existing shapes | | 'trash' | Delete the currently selected feature |

Text Notation

When notation mode is active, clicking the map places a point feature. An editor popup automatically opens allowing the user to configure:

  • Text content — the label displayed on the map
  • Font size — 12px to 32px
  • Color — preset palette or custom hex color picker

Text notations are exported as GeoJSON Point features with isNotation: true in properties.

{
  "type": "Feature",
  "properties": {
    "isNotation": true,
    "notationText": "Headquarters",
    "notationSize": 16,
    "notationColor": "#6366f1"
  },
  "geometry": {
    "type": "Point",
    "coordinates": [78.9629, 20.5937]
  }
}

3. DrawingController Public API

| Method | Signature | Description | |:-------|:----------|:------------| | setMode | (mode: 'polygon' \| 'circle' \| 'notation' \| 'select' \| 'trash') => void | Activate a drawing or editing mode | | getAllFeatures | () => FeatureCollection | Get all drawn features as a GeoJSON FeatureCollection | | addFeatures | (features: FeatureCollection) => void | Load GeoJSON features onto the drawing canvas | | deleteFeature | (id: string) => void | Remove a specific feature by ID | | clear | () => void | Remove all features from the drawing canvas | | destroy | () => void | Cleanup all event listeners, popups, toolbar, and remove the draw control | | draw (field) | MapboxDraw | Direct access to the underlying MapboxDraw instance for advanced use |


4. Spatial Clustering Engine

Handle up to 10,000+ points dynamically. By default, it aggregates based on the native feature count (point_count). You can also supply custom properties and weighting:

import { ClusterController } from '@sovereignsolutions/ss-map-gl';

// A. Default: Count-based clustering (No extra configuration needed)
const clusterController = new ClusterController(mapEngine, {
  clusterRadius: 50,
  clusterMaxZoom: 14,
  badgeRenderer: (count) => {
    // badgeRenderer receives the count of points in the cluster
    if (count < 100) return { color: '#6366f1', radius: 18 };
    if (count < 500) return { color: '#3b82f6', radius: 24 };
    return { color: '#ef4444', radius: 32, borderWidth: 3, borderColor: '#ffffff' };
  }
});

// B. Custom Weighting: Clustering based on custom property sums
const weightedClusterController = new ClusterController(mapEngine, {
  clusterRadius: 50,
  clusterMaxZoom: 14,
  clusterValueProperty: 'total_value',
  clusterProperties: {
    // Sum the custom "value" of clustered pins, falling back to 1 if missing
    total_value: ['+', ['coalesce', ['get', 'value'], 1]]
  },
  badgeRenderer: (value) => {
    // badgeRenderer receives the custom total_value sum
    if (value < 1000) return { color: '#6366f1', radius: 18 };
    return { color: '#ef4444', radius: 32 };
  }
});

🔔 Event Contract & Lifecycle Hooks

The SDK provides direct callback event interfaces for all drawing interactions and map viewport lifecycle changes:

| Callback Hook | Event Type | Description | Argument Signature | | :--- | :--- | :--- | :--- | | onDrawStart | Drawing Mode | User entered a drawing state | (mode: string) => void | | onDrawComplete | Draw Complete | Shape finished drawing and added to map | (features: Feature[]) => void | | onDrawCreate | Draw Create | Raw draw.create event (all shape types) | (features: Feature[]) => void | | onDrawUpdate | Draw Update | Raw draw.update event | (features: Feature[]) => void | | onDrawDelete | Draw Delete | Raw draw.delete event | (features: Feature[]) => void | | onShapeSelect | Shape Select | User clicked/selected a shape on map | (features: Feature[]) => void | | onShapeUpdate | Shape Update | Shape vertex dragged, circle resized, or moved | (features: Feature[]) => void | | onShapeDelete | Shape Delete | User deleted a shape from the map | (features: Feature[]) => void | | onModeChange | Mode Change | SDK changed drawing mode internally (e.g. after shape completes) | (mode: string) => void | | onDrag | Viewport Hook | Map viewport was panned/dragged | () => void | | onZoom | Viewport Hook | Map viewport was zoomed | () => void | | onBoundsChange | Viewport Hook | Viewport bounds changed (at end of pan/zoom) | (bounds: ViewportBounds) => void |


🌐 GeoJSON & Data Formats

1. Polygon Export Format

{
  "type": "Feature",
  "properties": {
    "fillColor": "#6366f1",
    "strokeColor": "#4f46e5",
    "strokeWidth": 2
  },
  "geometry": {
    "type": "Polygon",
    "coordinates": [[[78.9, 20.5], [79.1, 20.5], [79.0, 20.7], [78.9, 20.5]]]
  }
}

2. Circle Export Format

Circles are serialized as a Polygon representing a 64-vertex approximation, with circle metadata preserved in properties for future editable re-imports:

{
  "type": "Feature",
  "id": "circle-xyz123",
  "properties": {
    "isCircle": true,
    "center": [78.9629, 20.5937],
    "radius": 1500.5
  },
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [[78.9629, 20.607], [79.076, 20.5937], "...", [78.9629, 20.607]]
    ]
  }
}

3. Text Notation Export Format

{
  "type": "Feature",
  "properties": {
    "isNotation": true,
    "notationText": "Label text here",
    "notationSize": 16,
    "notationColor": "#6366f1"
  },
  "geometry": {
    "type": "Point",
    "coordinates": [78.9629, 20.5937]
  }
}

4. Industry Standard Point-Radius Import Format

The SDK also imports standard Point objects containing a radius parameter:

{
  "type": "Feature",
  "properties": {
    "radius": 2000
  },
  "geometry": {
    "type": "Point",
    "coordinates": [78.9629, 20.5937]
  }
}

Note: Upon calling GeoJsonSerializer.importFromGeoJson(), this Point structure is automatically reconstructed into an editable 64-vertex circle shape.

5. Cluster Data Format

Input points for the clustering engine use the following format:

interface ClusterPoint {
  coordinates: [number, number]; // [longitude, latitude]
  value?: number;                // Optional custom value/weight property
  properties?: Record<string, any>; // Optional user-defined properties
}

🔄 Dataset Update Usage

Consume the safe point update API to dynamically swap or refresh coordinates. This operation uses MapLibre's setData under the hood, preventing canvas flicker, duplicate layers, or broken Supercluster states:

// Replace point dataset safely (displays count by default)
clusterController.setPoints([
  { coordinates: [78.96, 20.59] },
  { coordinates: [79.00, 20.60] }
]);

🧹 Cleanup & Unmount Behavior

To unmount maps and drawing controllers safely without leaks, invoke destroy() to remove layers, markers, listeners, controls, and DOM elements:

// Unmount Drawing Controller and toolbar
drawingController.destroy();

// Unmount Cluster Controller layers and event listeners
clusterController.destroy();

// Terminate MapLibre GL Instance
mapEngine.destroy();

⚠️ Known Limitations

  1. Circle Approximation: Circles are represented as 64-vertex polygons. Resizing calculation works smoothly, but fine coordinate precision is subject to 64-segment resolution.
  2. Global Cursor Style conflicts: When switching modes, Mapbox GL Draw alters CSS pointer styles. Hover interactions on clusters overlay standard pointer rules.
  3. Text Notation rendering: Notation labels are rendered using MapLibre symbol layers. Label visibility at very small zoom levels depends on the active base map style's collision detection settings.

📊 QA & Performance Evidence

  • Dataset Size Tested: 10,000+ coordinates loaded.
  • Browser/Device Used: Chrome (Version 126.0), Windows 11 Enterprise (Intel Core i7, 32GB RAM).
  • Render Timing & FPS:
    • Point indexing via Supercluster finishes in under 15ms.
    • Frame rates remain at solid 60 FPS during map pans and zoom actions.
  • Cluster Interaction Result: Smooth map transition with easeTo animation (duration 800ms) upon tapping clusters.
  • GeoJSON Round-Trip: Checked round-trips for imported points and exported polygons with 100% geometry recovery.
  • Cleanup & Remount: Confirmed through browser developer tools that garbage collection completely reclaims map memory after calling destroy().

📦 Changelog

v1.0.7

  • 🎨 Editor popup now forces light theme (color-scheme: light) on all form controls — fully compatible with dark-mode host applications
  • ✨ Replaced native <select> size picker with a custom-styled dropdown component: rounded corners, smooth hover/selected states, consistent white background
  • 🐛 Fixed: text input and size dropdown now show correct borders and matching focus highlight (#6366f1)
  • ✨ Added onModeChange callback — fires when SDK changes drawing mode internally (e.g. after a shape is completed), useful for syncing custom toolbars
  • 🐛 Fixed: Save button height misalignment with Cancel/Delete buttons in editor popup

v1.0.6

  • ✨ Added Text Notation drawing mode (setMode('notation')) — place editable text labels directly on the map
  • ✨ Notation editor popup with live preview: text content, font size (12–32px), color picker with preset palette
  • 🐛 Fixed: existing features no longer disappear when switching into Text Notation mode
  • 🐛 Fixed: notation mode cursor now changes to crosshair (+) when hovering over the map

v1.0.5

  • 🐛 Fixed map crash when entering circle mode with empty coordinates

v1.0.4

  • ✨ Initial public release with polygon drawing, circle drawing, clustering, and GeoJSON serialization