@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.
Keywords
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-gl2. 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:
3DBASICBRIGHTDARKFIORDLIBERTYPOSITRONTERRAINTONER
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
- Circle Approximation: Circles are represented as 64-vertex polygons. Resizing calculation works smoothly, but fine coordinate precision is subject to 64-segment resolution.
- Global Cursor Style conflicts: When switching modes, Mapbox GL Draw alters CSS pointer styles. Hover interactions on clusters overlay standard pointer rules.
- Text Notation rendering: Notation labels are rendered using MapLibre
symbollayers. 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
onModeChangecallback — 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
