map-gl-offline 0.5.5 โ 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -444
- package/dist/index.d.ts +17 -8
- package/dist/index.esm.js +2600 -2646
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2604 -2645
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +2604 -2645
- package/dist/index.umd.js.map +1 -1
- package/dist/managers/offlineMapManager/index.d.ts +3 -57
- package/dist/managers/offlineMapManager/regionManagement.d.ts +3 -2
- package/dist/managers/offlineMapManager/resourceManagement.d.ts +4 -4
- package/dist/services/regionService.d.ts +30 -2
- package/dist/services/resourceService.d.ts +4 -4
- package/dist/storage/indexedDbManager.d.ts +18 -15
- package/dist/style.css +1 -1
- package/dist/types/region.d.ts +49 -0
- package/dist/types/tile.d.ts +15 -0
- package/dist/ui/managers/downloadManager.d.ts +0 -5
- package/dist/ui/offlineManagerControl.d.ts +0 -11
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/styleUtils.d.ts +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,93 +4,35 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://www.typescriptlang.org/)
|
|
6
6
|
|
|
7
|
-
**[Documentation](https://map-gl-offline.netlify.app)**
|
|
7
|
+
**[๐ Documentation](https://map-gl-offline.netlify.app)** ยท **[๐ฎ Live Demo](https://map-gl-offline-demo.netlify.app)** ยท **[๐ Issues](https://github.com/muimsd/map-gl-offline/issues)**
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## ๐ฌ Demo
|
|
9
|
+
TypeScript offline-map library for **MapLibre GL JS** and **Mapbox GL JS**. Download styles, tiles, sprites, glyphs, and fonts to IndexedDB; load them back with zero network. Ships with a glassmorphic UI control and a complete programmatic API.
|
|
12
10
|
|
|
13
11
|

|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
## โจ Features
|
|
18
|
-
|
|
19
|
-
### ๐ฏ Core Offline Capabilities
|
|
20
|
-
|
|
21
|
-
- ๐บ๏ธ **Complete Offline Maps**: Download and store entire map regions with polygon-based selection
|
|
22
|
-
- ๐ฏ **Smart Tile Management**: Efficient vector/raster tile downloading, caching, and retrieval with zoom-level optimization
|
|
23
|
-
- ๐งฉ **Extra Tile Sources**: Save additional vector (MVT/PBF) and raster tile layers alongside the style's own sources
|
|
24
|
-
- ๐ค **Font & Glyph Support**: Comprehensive font and glyph management with Unicode range support
|
|
25
|
-
- ๐จ **Sprite Management**: Handle map sprites and icons offline with multi-resolution support (@1x, @2x)
|
|
26
|
-
- ๐ **Real-time Analytics**: Detailed storage analytics, performance metrics, and optimization recommendations
|
|
27
|
-
|
|
28
|
-
### ๐ Mapbox GL JS Support
|
|
29
|
-
|
|
30
|
-
- ๐ **mapbox:// Protocol Resolution**: Automatic resolution of `mapbox://` style, source, sprite, and glyph URLs
|
|
31
|
-
- ๐๏ธ **Mapbox Standard Style**: Full support including 3D models, raster-dem terrain, and import-based style resolution
|
|
32
|
-
- ๐
**Day/Night Light Presets**: Toggle between day and night lighting in Mapbox Standard style
|
|
33
|
-
- ๐ง๏ธ **Weather Controls**: Rain and snow effects for Mapbox Standard style
|
|
34
|
-
- ๐ **Auto-detection**: Automatically detects whether a style is Mapbox or MapLibre and applies the correct handling
|
|
35
|
-
|
|
36
|
-
### ๐จ Modern UI Control
|
|
37
|
-
|
|
38
|
-
- ๐ผ๏ธ **Glassmorphic Design**: Beautiful modern interface with glassmorphism effects and smooth animations
|
|
39
|
-
- ๐ **Dark/Light Theme**: Automatic theme switching with system preference detection
|
|
40
|
-
- ๐ **Polygon Drawing**: Interactive polygon tool for precise region selection
|
|
41
|
-
- ๐ **Live Progress**: Real-time download progress with detailed statistics
|
|
42
|
-
- ๐ฏ **Region Management**: Easy-to-use interface for managing multiple offline regions
|
|
43
|
-
- โก **Responsive**: Mobile-friendly design that adapts to all screen sizes
|
|
44
|
-
- ๐ **Internationalization**: English and Arabic language support with full RTL layout
|
|
13
|
+
## Features
|
|
45
14
|
|
|
46
|
-
|
|
15
|
+
- ๐บ๏ธ **Offline regions** โ polygon selection, smart tile management, extra vector/raster overlays
|
|
16
|
+
- ๐จ **Full resource capture** โ styles, sprites, fonts, glyphs with Unicode ranges
|
|
17
|
+
- ๐ **Mapbox GL + MapLibre GL** โ auto-detection, `mapbox://` URL resolution, Standard style with 3D/terrain
|
|
18
|
+
- ๐ **Analytics & cleanup** โ storage reports, auto-cleanup, quota-aware downloads
|
|
19
|
+
- ๐จ **UI control** โ glassmorphic panel, dark/light themes, English/Arabic (RTL), polygon drawing
|
|
20
|
+
- ๐ ๏ธ **Programmatic API** โ `downloadRegion` with per-phase progress, full TypeScript types
|
|
47
21
|
|
|
48
|
-
|
|
49
|
-
- ๐ง **Full TypeScript**: Complete type definitions, interfaces, and compile-time safety
|
|
50
|
-
- โก **Performance Optimized**: Concurrent downloads, async/await patterns, and memory-efficient operations
|
|
51
|
-
- ๐งน **Intelligent Cleanup**: Smart cleanup of expired data with customizable policies
|
|
52
|
-
- ๐ **Robust Error Handling**: Comprehensive error recovery, retry mechanisms, and graceful degradation
|
|
53
|
-
- ๐ **Enhanced Logging**: Detailed debugging with zoom-level specific logging (Z12 tracking)
|
|
54
|
-
|
|
55
|
-
## ๐ฆ Installation
|
|
22
|
+
## Install
|
|
56
23
|
|
|
57
24
|
```bash
|
|
58
25
|
npm install map-gl-offline
|
|
59
|
-
# or
|
|
60
|
-
yarn add map-gl-offline
|
|
61
|
-
# or
|
|
62
|
-
pnpm add map-gl-offline
|
|
63
26
|
```
|
|
64
27
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
For use via `<script>` tag, the library is available as the `mapgloffline` global (similar to `mapboxgl` and `maplibregl`):
|
|
28
|
+
Or via CDN as the `mapgloffline` global:
|
|
68
29
|
|
|
69
30
|
```html
|
|
70
31
|
<script src="https://unpkg.com/map-gl-offline/dist/index.umd.js"></script>
|
|
71
32
|
<link rel="stylesheet" href="https://unpkg.com/map-gl-offline/style.css" />
|
|
72
|
-
<script>
|
|
73
|
-
const manager = new mapgloffline.OfflineMapManager();
|
|
74
|
-
const control = new mapgloffline.OfflineManagerControl(manager, {
|
|
75
|
-
styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
|
|
76
|
-
});
|
|
77
|
-
map.addControl(control, 'top-right');
|
|
78
|
-
</script>
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## ๐ Environment Setup
|
|
82
|
-
|
|
83
|
-
For development or when using Maptiler styles, create a `.env` file:
|
|
84
|
-
|
|
85
|
-
```env
|
|
86
|
-
VITE_MAPTILER_API_KEY=your_api_key_here
|
|
87
33
|
```
|
|
88
34
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
For Mapbox styles, you will also need a Mapbox access token from [Mapbox](https://www.mapbox.com/).
|
|
92
|
-
|
|
93
|
-
## ๐ Quick Start
|
|
35
|
+
## Quick Start
|
|
94
36
|
|
|
95
37
|
### MapLibre GL JS
|
|
96
38
|
|
|
@@ -100,11 +42,9 @@ import { OfflineMapManager, OfflineManagerControl } from 'map-gl-offline';
|
|
|
100
42
|
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
101
43
|
import 'map-gl-offline/style.css';
|
|
102
44
|
|
|
103
|
-
const styleUrl = 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_API_KEY';
|
|
104
|
-
|
|
105
45
|
const map = new maplibregl.Map({
|
|
106
46
|
container: 'map',
|
|
107
|
-
style:
|
|
47
|
+
style: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
|
|
108
48
|
center: [-74.006, 40.7128],
|
|
109
49
|
zoom: 12,
|
|
110
50
|
});
|
|
@@ -112,48 +52,33 @@ const map = new maplibregl.Map({
|
|
|
112
52
|
const offlineManager = new OfflineMapManager();
|
|
113
53
|
|
|
114
54
|
map.on('load', () => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
55
|
+
map.addControl(
|
|
56
|
+
new OfflineManagerControl(offlineManager, {
|
|
57
|
+
styleUrl: map.getStyle().sprite,
|
|
58
|
+
mapLib: maplibregl, // enables idb:// protocol
|
|
59
|
+
}),
|
|
60
|
+
'top-right',
|
|
61
|
+
);
|
|
122
62
|
});
|
|
123
63
|
```
|
|
124
64
|
|
|
125
65
|
### Mapbox GL JS
|
|
126
66
|
|
|
127
|
-
Mapbox GL JS v3
|
|
128
|
-
|
|
129
|
-
**Option 1: CLI (recommended)**
|
|
67
|
+
Mapbox GL JS v3 lacks `addProtocol`, so the library uses a Service Worker. Run **one** of:
|
|
130
68
|
|
|
131
69
|
```bash
|
|
132
|
-
npx map-gl-offline init
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
```js
|
|
138
|
-
// vite.config.js
|
|
139
|
-
import { offlineSwPlugin } from 'map-gl-offline/vite-plugin';
|
|
140
|
-
|
|
141
|
-
export default defineConfig({
|
|
142
|
-
plugins: [offlineSwPlugin()],
|
|
143
|
-
});
|
|
70
|
+
npx map-gl-offline init # CLI (recommended)
|
|
71
|
+
# or add to vite.config.js:
|
|
72
|
+
# import { offlineSwPlugin } from 'map-gl-offline/vite-plugin';
|
|
73
|
+
# plugins: [offlineSwPlugin()]
|
|
74
|
+
# or manually: cp node_modules/map-gl-offline/dist/idb-offline-sw.js public/
|
|
144
75
|
```
|
|
145
76
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
cp node_modules/map-gl-offline/dist/idb-offline-sw.js public/idb-offline-sw.js
|
|
150
|
-
```
|
|
77
|
+
Then:
|
|
151
78
|
|
|
152
79
|
```typescript
|
|
153
80
|
import mapboxgl from 'mapbox-gl';
|
|
154
81
|
import { OfflineMapManager, OfflineManagerControl } from 'map-gl-offline';
|
|
155
|
-
import 'mapbox-gl/dist/mapbox-gl.css';
|
|
156
|
-
import 'map-gl-offline/style.css';
|
|
157
82
|
|
|
158
83
|
mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';
|
|
159
84
|
|
|
@@ -165,381 +90,103 @@ const map = new mapboxgl.Map({
|
|
|
165
90
|
});
|
|
166
91
|
|
|
167
92
|
const offlineManager = new OfflineMapManager();
|
|
168
|
-
|
|
169
|
-
map.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
});
|
|
178
|
-
map.addControl(control, 'top-right');
|
|
179
|
-
});
|
|
93
|
+
map.on('load', () =>
|
|
94
|
+
map.addControl(
|
|
95
|
+
new OfflineManagerControl(offlineManager, {
|
|
96
|
+
styleUrl: 'mapbox://styles/mapbox/standard',
|
|
97
|
+
accessToken: mapboxgl.accessToken,
|
|
98
|
+
}),
|
|
99
|
+
'top-right',
|
|
100
|
+
),
|
|
101
|
+
);
|
|
180
102
|
```
|
|
181
103
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
The UI control provides:
|
|
185
|
-
|
|
186
|
-
- ๐ **Polygon drawing** for region selection
|
|
187
|
-
- ๐ **Download progress** tracking
|
|
188
|
-
- ๐๏ธ **Region management** (view, delete)
|
|
189
|
-
- ๐ **Theme toggle** (dark/light mode)
|
|
190
|
-
- ๐ **Storage analytics**
|
|
191
|
-
- ๐ **Language switcher** (English / Arabic with RTL)
|
|
104
|
+
## Programmatic Usage
|
|
192
105
|
|
|
193
|
-
|
|
106
|
+
`downloadRegion` runs the full pipeline (**style โ sprites โ glyphs โ tiles โ metadata**) with per-phase progress. `addRegion` alone only stores metadata โ use `downloadRegion` to actually fetch assets.
|
|
194
107
|
|
|
195
108
|
```typescript
|
|
196
109
|
import { OfflineMapManager } from 'map-gl-offline';
|
|
197
110
|
|
|
198
|
-
// Initialize the offline manager
|
|
199
111
|
const offlineManager = new OfflineMapManager();
|
|
200
112
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
minZoom: 10,
|
|
210
|
-
maxZoom: 16,
|
|
211
|
-
styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
|
|
212
|
-
onProgress: progress => {
|
|
213
|
-
console.log(`Progress: ${progress.percentage}%`);
|
|
214
|
-
console.log(`Current: ${progress.message}`);
|
|
113
|
+
await offlineManager.downloadRegion(
|
|
114
|
+
{
|
|
115
|
+
id: 'downtown',
|
|
116
|
+
name: 'Downtown',
|
|
117
|
+
bounds: [[-74.0559, 40.7128], [-74.0059, 40.7628]],
|
|
118
|
+
minZoom: 10,
|
|
119
|
+
maxZoom: 16,
|
|
120
|
+
styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
|
|
215
121
|
},
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// List all regions
|
|
225
|
-
const regions = await offlineManager.listStoredRegions();
|
|
226
|
-
console.log(`Stored regions:`, regions);
|
|
122
|
+
{
|
|
123
|
+
onProgress: ({ phase, percentage, message }) => {
|
|
124
|
+
console.log(`[${phase}] ${percentage.toFixed(1)}% ${message ?? ''}`);
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
);
|
|
227
128
|
|
|
228
|
-
//
|
|
129
|
+
// Manage
|
|
130
|
+
await offlineManager.listStoredRegions();
|
|
131
|
+
await offlineManager.getStoredRegion('downtown');
|
|
229
132
|
await offlineManager.deleteRegion('downtown');
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Analytics & Monitoring
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
// Get comprehensive storage analytics
|
|
236
|
-
const analytics = await offlineManager.getComprehensiveStorageAnalytics();
|
|
237
|
-
console.log(`Total storage: ${analytics.totalStorageSize} bytes`);
|
|
238
|
-
console.log(`Tiles: ${analytics.tiles.count} (${analytics.tiles.totalSize} bytes)`);
|
|
239
|
-
console.log(`Fonts: ${analytics.fonts.count} (${analytics.fonts.totalSize} bytes)`);
|
|
240
|
-
console.log(`Sprites: ${analytics.sprites.count} (${analytics.sprites.totalSize} bytes)`);
|
|
241
|
-
console.log(`Recommendations:`, analytics.recommendations);
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### Cleanup & Maintenance
|
|
245
|
-
|
|
246
|
-
```typescript
|
|
247
|
-
// Clean up expired regions
|
|
248
|
-
const deletedCount = await offlineManager.cleanupExpiredRegions();
|
|
249
|
-
console.log(`Cleaned ${deletedCount} expired regions`);
|
|
250
|
-
|
|
251
|
-
// Verify and repair fonts
|
|
252
|
-
const verification = await offlineManager.verifyAndRepairFonts('style_123', { removeCorrupted: true });
|
|
253
|
-
console.log(`Verified: ${verification.verified}, Repaired: ${verification.repaired}, Removed: ${verification.removed}`);
|
|
254
|
-
|
|
255
|
-
// Set up automatic cleanup (runs every 24 hours)
|
|
256
|
-
const cleanupId = await offlineManager.setupAutoCleanup({
|
|
257
|
-
intervalHours: 24,
|
|
258
|
-
maxAge: 30, // days
|
|
259
|
-
});
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
## ๐ API Reference
|
|
263
|
-
|
|
264
|
-
### OfflineMapManager
|
|
265
|
-
|
|
266
|
-
Main class for managing offline maps.
|
|
267
|
-
|
|
268
|
-
**Constructor:**
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
const manager = new OfflineMapManager(overrides?: OfflineManagerServiceOverrides);
|
|
272
|
-
```
|
|
273
133
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
- `addRegion(options: OfflineRegionOptions)` - Download and store a map region
|
|
279
|
-
- `getStoredRegion(id: string)` - Retrieve a stored region by ID
|
|
280
|
-
- `deleteRegion(id: string)` - Delete a specific region and its resources
|
|
281
|
-
- `listStoredRegions()` - List all stored regions with metadata
|
|
282
|
-
- `listRegions()` - List all region options
|
|
283
|
-
|
|
284
|
-
**Analytics Methods:**
|
|
285
|
-
|
|
286
|
-
- `getComprehensiveStorageAnalytics()` - Get detailed storage statistics
|
|
287
|
-
- `getRegionAnalytics()` - Get aggregate analytics across all regions
|
|
288
|
-
- `getTileStatistics(styleId: string)` - Get tile-specific statistics
|
|
289
|
-
- `getFontStatistics(styleId: string)` - Get font statistics
|
|
290
|
-
- `getSpriteStatistics(styleId: string)` - Get sprite statistics
|
|
291
|
-
|
|
292
|
-
**Cleanup & Maintenance Methods:**
|
|
293
|
-
|
|
294
|
-
- `cleanupExpiredRegions()` - Remove regions past expiration date
|
|
295
|
-
- `performSmartCleanup(options)` - Intelligent cleanup with configurable criteria
|
|
296
|
-
- `cleanupOldFonts(styleId?, options?)` - Remove old font data
|
|
297
|
-
- `cleanupOldSprites(styleId?, options?)` - Remove old sprite data
|
|
298
|
-
- `cleanupOldGlyphs(styleId?, options?)` - Remove old glyph data
|
|
299
|
-
- `verifyAndRepairFonts(styleId, options?)` - Verify font integrity
|
|
300
|
-
- `verifyAndRepairSprites(styleId, options?)` - Verify sprite integrity
|
|
301
|
-
- `verifyAndRepairGlyphs(styleId, options?)` - Verify glyph integrity
|
|
302
|
-
- `setupAutoCleanup(options)` - Enable automatic periodic cleanup
|
|
303
|
-
- `stopAutoCleanup(cleanupId?)` - Disable a specific auto-cleanup
|
|
304
|
-
- `stopAllAutoCleanup()` - Disable all auto-cleanups
|
|
305
|
-
- `performCompleteMaintenance(options?)` - Run comprehensive maintenance
|
|
306
|
-
|
|
307
|
-
### OfflineManagerControl
|
|
308
|
-
|
|
309
|
-
UI control for MapLibre GL JS and Mapbox GL JS with glassmorphic design.
|
|
310
|
-
|
|
311
|
-
**Constructor:**
|
|
312
|
-
|
|
313
|
-
```typescript
|
|
314
|
-
const offlineManager = new OfflineMapManager();
|
|
315
|
-
|
|
316
|
-
const control = new OfflineManagerControl(offlineManager, {
|
|
317
|
-
styleUrl: 'https://example.com/style.json', // Map style URL (required)
|
|
318
|
-
theme?: 'light' | 'dark', // UI theme (default: 'dark')
|
|
319
|
-
showBbox?: boolean, // Show region bounding boxes (default: false)
|
|
320
|
-
accessToken?: string, // Mapbox access token (for mapbox:// URLs)
|
|
321
|
-
mapLib?: MapLibProtocol, // Map library module (e.g. maplibregl) for idb:// protocol
|
|
322
|
-
});
|
|
134
|
+
// Analytics & cleanup
|
|
135
|
+
await offlineManager.getComprehensiveStorageAnalytics();
|
|
136
|
+
await offlineManager.cleanupExpiredRegions();
|
|
137
|
+
await offlineManager.setupAutoCleanup({ intervalHours: 24, maxAge: 30 });
|
|
323
138
|
```
|
|
324
139
|
|
|
325
|
-
|
|
140
|
+
### Sparse-source detection
|
|
326
141
|
|
|
327
|
-
-
|
|
328
|
-
- Real-time download progress tracking
|
|
329
|
-
- Region management (view, delete)
|
|
330
|
-
- Theme toggle (dark/light mode)
|
|
331
|
-
- Storage analytics display
|
|
332
|
-
- Language switcher (English / Arabic with RTL support)
|
|
333
|
-
- Responsive mobile-friendly design
|
|
142
|
+
For composite styles (e.g. Mapbox Standard) that reference sparse tilesets like `indoor-v3` or `landmark-pois-v1`, the tile downloader probes start/middle/end tiles per source and drops any that return majority-404. Disable with `tileOptions: { probeSourcesBeforeDownload: false }`.
|
|
334
143
|
|
|
335
|
-
|
|
144
|
+
### Recovering from an incompatible DB
|
|
336
145
|
|
|
337
|
-
|
|
146
|
+
If another app on the same origin has created `offline-map-db` at a newer version, `dbPromise` throws a typed error. Offer a reset UX:
|
|
338
147
|
|
|
339
148
|
```typescript
|
|
340
|
-
|
|
341
|
-
id: string; // Unique region identifier
|
|
342
|
-
name: string; // Human-readable name (required)
|
|
343
|
-
bounds: [[number, number], [number, number]]; // [[lng, lat], [lng, lat]]
|
|
344
|
-
minZoom: number; // Minimum zoom level (e.g., 10)
|
|
345
|
-
maxZoom: number; // Maximum zoom level (e.g., 16)
|
|
346
|
-
styleUrl?: string; // Map style URL
|
|
347
|
-
expiry?: number; // Expiration timestamp (ms since epoch)
|
|
348
|
-
deleteOnExpiry?: boolean; // Auto-delete on expiration
|
|
349
|
-
multipleRegions?: boolean; // Part of a multi-region download
|
|
350
|
-
tileExtension?: string; // Tile extension (pbf, mvt, png, etc.)
|
|
351
|
-
extraSources?: ExtraSource[]; // Additional tile sources to download alongside the style
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
interface ExtraSource {
|
|
355
|
-
id: string; // Unique source identifier
|
|
356
|
-
type?: 'vector' | 'raster' | 'raster-dem'; // Defaults to 'vector'
|
|
357
|
-
tiles: string[]; // Tile URL templates with {z}/{x}/{y}
|
|
358
|
-
minzoom?: number;
|
|
359
|
-
maxzoom?: number;
|
|
360
|
-
attribution?: string;
|
|
361
|
-
}
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
### Extra Tile Sources
|
|
365
|
-
|
|
366
|
-
Save additional vector or raster layers (e.g. custom overlays) alongside the style's own sources:
|
|
367
|
-
|
|
368
|
-
```typescript
|
|
369
|
-
await manager.addRegion({
|
|
370
|
-
id: 'downtown',
|
|
371
|
-
name: 'Downtown',
|
|
372
|
-
bounds: [[-74.05, 40.71], [-74.00, 40.76]],
|
|
373
|
-
minZoom: 10,
|
|
374
|
-
maxZoom: 16,
|
|
375
|
-
styleUrl: 'https://example.com/style.json',
|
|
376
|
-
extraSources: [
|
|
377
|
-
{
|
|
378
|
-
id: 'buildings',
|
|
379
|
-
type: 'vector',
|
|
380
|
-
tiles: ['https://tiles.example.com/buildings/{z}/{x}/{y}.pbf'],
|
|
381
|
-
minzoom: 13,
|
|
382
|
-
maxzoom: 16,
|
|
383
|
-
},
|
|
384
|
-
],
|
|
385
|
-
});
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
When using the `OfflineManagerControl`, the region download form auto-discovers tile sources on the live map and shows them as checkboxes โ users pick which extra layers to include.
|
|
389
|
-
|
|
390
|
-
## ๐ฏ Use Cases
|
|
391
|
-
|
|
392
|
-
- ๐๏ธ **Outdoor & Recreation Apps**: Hiking, camping, and adventure apps with offline trail maps
|
|
393
|
-
- ๐ฑ **Field Data Collection**: Survey and data collection in remote areas
|
|
394
|
-
- ๐จ **Emergency Response**: Critical map access during network outages
|
|
395
|
-
- โ๏ธ **Travel Apps**: Tourist apps with offline city maps
|
|
396
|
-
- ๐ **Fleet Management**: Vehicle tracking with offline map fallback
|
|
397
|
-
- ๐ **Asset Management**: Field service apps with offline capability
|
|
398
|
-
- ๐ **Educational Apps**: Geography and learning apps with downloadable maps
|
|
399
|
-
- ๐๏ธ **Construction & Engineering**: Site management with offline blueprints
|
|
400
|
-
- ๐พ **Bandwidth Optimization**: Reduce data costs by pre-downloading maps
|
|
401
|
-
|
|
402
|
-
## ๐ก Best Practices
|
|
149
|
+
import { dbPromise, OfflineMapDBVersionError, resetOfflineMapDB } from 'map-gl-offline';
|
|
403
150
|
|
|
404
|
-
### Performance Optimization
|
|
405
|
-
|
|
406
|
-
```typescript
|
|
407
|
-
// Balance quality vs storage with appropriate zoom levels
|
|
408
|
-
const region = {
|
|
409
|
-
minZoom: 10, // Don't go too low (tile count grows exponentially)
|
|
410
|
-
maxZoom: 16, // Don't go too high (diminishing returns)
|
|
411
|
-
bounds: [
|
|
412
|
-
/* ... */
|
|
413
|
-
],
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
// Monitor storage usage
|
|
417
|
-
const analytics = await manager.getComprehensiveStorageAnalytics();
|
|
418
|
-
if (analytics.totalStorageSize > 500 * 1024 * 1024) {
|
|
419
|
-
console.warn('High storage usage detected');
|
|
420
|
-
await manager.performSmartCleanup({ maxStorageSize: 500 * 1024 * 1024 });
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Use progressive loading for better UX
|
|
424
|
-
const progressiveDownload = {
|
|
425
|
-
priorityZoomLevels: [12, 13, 11, 14, 10, 15, 16],
|
|
426
|
-
onProgress: p => updateUI(p),
|
|
427
|
-
};
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
### Error Handling
|
|
431
|
-
|
|
432
|
-
```typescript
|
|
433
151
|
try {
|
|
434
|
-
await
|
|
435
|
-
} catch (
|
|
436
|
-
if (
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
} else {
|
|
442
|
-
console.error('Unexpected error:', error);
|
|
152
|
+
await dbPromise;
|
|
153
|
+
} catch (err) {
|
|
154
|
+
if (err instanceof OfflineMapDBVersionError) {
|
|
155
|
+
if (confirm('Offline storage is incompatible. Clear it?')) {
|
|
156
|
+
await resetOfflineMapDB(); // destructive
|
|
157
|
+
location.reload();
|
|
158
|
+
}
|
|
443
159
|
}
|
|
444
160
|
}
|
|
445
161
|
```
|
|
446
162
|
|
|
447
|
-
##
|
|
448
|
-
|
|
449
|
-
| Browser | Version | Support |
|
|
450
|
-
| ------- | ------- | ------- |
|
|
451
|
-
| Chrome | 51+ | โ
|
|
|
452
|
-
| Firefox | 45+ | โ
|
|
|
453
|
-
| Safari | 10+ | โ
|
|
|
454
|
-
| Edge | 79+ | โ
|
|
|
455
|
-
| Mobile | Modern | โ
|
|
|
163
|
+
## API at a glance
|
|
456
164
|
|
|
457
|
-
**
|
|
165
|
+
- **Regions** โ `downloadRegion`, `loadRegion`, `addRegion`, `getStoredRegion`, `listStoredRegions`, `listRegions`, `deleteRegion`
|
|
166
|
+
- **Analytics** โ `getComprehensiveStorageAnalytics`, `getRegionAnalytics`, `getTileStats`, `getFontStats`, `getSpriteStats`, `getGlyphStats`
|
|
167
|
+
- **Cleanup** โ `cleanupExpiredRegions`, `performSmartCleanup`, `cleanupOld{Fonts,Sprites,Glyphs}`, `verifyAndRepair{Fonts,Sprites,Glyphs}`, `setupAutoCleanup`, `performCompleteMaintenance`
|
|
168
|
+
- **Import / Export** โ `exportRegionAsJSON`, `exportRegionAsPMTiles`, `exportRegionAsMBTiles`, `importRegion`
|
|
169
|
+
- **Storage utilities** โ `dbPromise`, `OfflineMapDBVersionError`, `resetOfflineMapDB`, `loadAllStoredRegions`, `resourceKeyBelongsToStyle`
|
|
458
170
|
|
|
459
|
-
-
|
|
460
|
-
- ES2015+ JavaScript
|
|
461
|
-
- Async/await support
|
|
462
|
-
- Web Workers (optional, for background tasks)
|
|
171
|
+
See the **[full API reference](https://map-gl-offline.netlify.app/docs/api-reference)** and **[examples](https://map-gl-offline.netlify.app/docs/examples)** for every option and pattern.
|
|
463
172
|
|
|
464
|
-
##
|
|
173
|
+
## Browser compatibility
|
|
465
174
|
|
|
466
|
-
|
|
175
|
+
Chrome 51+ ยท Firefox 45+ ยท Safari 10+ ยท Edge 79+ ยท modern mobile browsers. Requires IndexedDB and ES2015+.
|
|
467
176
|
|
|
468
|
-
|
|
177
|
+
## Contributing
|
|
469
178
|
|
|
470
179
|
```bash
|
|
471
|
-
# Clone repository
|
|
472
180
|
git clone https://github.com/muimsd/map-gl-offline.git
|
|
473
|
-
cd map-gl-offline
|
|
474
|
-
|
|
475
|
-
#
|
|
476
|
-
npm
|
|
477
|
-
|
|
478
|
-
# Run development server
|
|
479
|
-
npm run dev
|
|
480
|
-
|
|
481
|
-
# Run tests
|
|
482
|
-
npm test
|
|
483
|
-
|
|
484
|
-
# Build library
|
|
485
|
-
npm run build
|
|
486
|
-
|
|
487
|
-
# Run MapLibre example app
|
|
488
|
-
cd examples/maplibre
|
|
489
|
-
npm install
|
|
490
|
-
npm run dev
|
|
181
|
+
cd map-gl-offline && npm install
|
|
182
|
+
npm run dev # dev harness
|
|
183
|
+
npm test # unit tests
|
|
184
|
+
npm run build # library
|
|
491
185
|
```
|
|
492
186
|
|
|
493
|
-
|
|
187
|
+
Issues and PRs welcome. See [CHANGELOG.md](CHANGELOG.md) for release notes.
|
|
494
188
|
|
|
495
|
-
|
|
496
|
-
map-gl-offline/
|
|
497
|
-
โโโ src/
|
|
498
|
-
โ โโโ managers/ # Core offline manager
|
|
499
|
-
โ โโโ services/ # Tile, font, sprite services
|
|
500
|
-
โ โโโ storage/ # IndexedDB management
|
|
501
|
-
โ โโโ ui/ # UI components & controls
|
|
502
|
-
โ โ โโโ translations/ # i18n (English, Arabic)
|
|
503
|
-
โ โโโ utils/ # Utilities & helpers
|
|
504
|
-
โ โโโ types/ # TypeScript definitions
|
|
505
|
-
โโโ bin/ # CLI (map-gl-offline init) & Vite plugin
|
|
506
|
-
โโโ examples/
|
|
507
|
-
โ โโโ maplibre/ # MapLibre GL JS example app
|
|
508
|
-
โ โโโ mapbox-gl/ # Mapbox GL JS example app
|
|
509
|
-
โโโ docs/ # Docusaurus documentation site
|
|
510
|
-
โโโ tests/ # Test suites
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
## ๐ Support & Links
|
|
514
|
-
|
|
515
|
-
- ๐ [Documentation](https://map-gl-offline.netlify.app)
|
|
516
|
-
- ๐ฎ [Live Demo](https://map-gl-offline-demo.netlify.app)
|
|
517
|
-
- ๐ [Report Issues](https://github.com/muimsd/map-gl-offline/issues)
|
|
518
|
-
- ๐ฌ [Discussions](https://github.com/muimsd/map-gl-offline/discussions)
|
|
519
|
-
- โญ [Feature Requests](https://github.com/muimsd/map-gl-offline/issues/new)
|
|
520
|
-
- ๐ [Star on GitHub](https://github.com/muimsd/map-gl-offline)
|
|
521
|
-
|
|
522
|
-
## ๐ Recent Updates
|
|
523
|
-
|
|
524
|
-
See [CHANGELOG.md](CHANGELOG.md) for complete version history.
|
|
525
|
-
|
|
526
|
-
**v0.5.5 (Latest):** Extra tile source selection for offline regions โ pick additional vector/raster layers to download alongside the style's own sources.
|
|
527
|
-
|
|
528
|
-
**v0.5.3:** 28% bundle size reduction (783 KB to 565 KB), 20+ bug fixes, XSS prevention, import atomicity, `@/` path alias for all imports.
|
|
529
|
-
|
|
530
|
-
**v0.5.2:** CLI command (`npx map-gl-offline init`), Vite plugin for Service Worker, Mapbox GL example app.
|
|
531
|
-
|
|
532
|
-
**v0.5.0:** Mapbox GL JS support, Standard style with 3D/terrain, day/night presets, rain/snow, i18n (English & Arabic with RTL).
|
|
533
|
-
|
|
534
|
-
## ๐ Acknowledgments
|
|
535
|
-
|
|
536
|
-
- [MapLibre GL JS](https://github.com/maplibre/maplibre-gl-js) - Open-source map rendering engine
|
|
537
|
-
- [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js) - Commercial map rendering engine
|
|
538
|
-
- [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) - Browser storage API
|
|
539
|
-
- [Tilebelt](https://github.com/mapbox/tilebelt) - Tile coordinate utilities
|
|
540
|
-
- [Tailwind CSS](https://tailwindcss.com/) - Utility-first CSS framework
|
|
541
|
-
|
|
542
|
-
## ๐ License
|
|
189
|
+
## License
|
|
543
190
|
|
|
544
191
|
MIT ยฉ [Muhammad Imran Siddique](https://github.com/muimsd)
|
|
545
192
|
|
|
@@ -547,10 +194,8 @@ MIT ยฉ [Muhammad Imran Siddique](https://github.com/muimsd)
|
|
|
547
194
|
|
|
548
195
|
<div align="center">
|
|
549
196
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
[๐ Documentation](https://map-gl-offline.netlify.app) โข [๐ฎ Live Demo](https://map-gl-offline-demo.netlify.app) โข [โญ Star on GitHub](https://github.com/muimsd/map-gl-offline)
|
|
197
|
+
[๐ Docs](https://map-gl-offline.netlify.app) ยท [๐ฎ Demo](https://map-gl-offline-demo.netlify.app) ยท [โญ GitHub](https://github.com/muimsd/map-gl-offline)
|
|
553
198
|
|
|
554
|
-
<a href="https://www.buymeacoffee.com/muimsd" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height:
|
|
199
|
+
<a href="https://www.buymeacoffee.com/muimsd" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 45px;"></a>
|
|
555
200
|
|
|
556
201
|
</div>
|
package/dist/index.d.ts
CHANGED
|
@@ -34,14 +34,23 @@
|
|
|
34
34
|
* ```typescript
|
|
35
35
|
* const offlineManager = new OfflineMapManager();
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
37
|
+
* // downloadRegion runs the full pipeline: style (if missing) โ sprites โ glyphs โ tiles โ metadata.
|
|
38
|
+
* // addRegion on its own only stores metadata; use downloadRegion to actually fetch assets.
|
|
39
|
+
* await offlineManager.downloadRegion(
|
|
40
|
+
* {
|
|
41
|
+
* id: 'sf',
|
|
42
|
+
* name: 'San Francisco',
|
|
43
|
+
* bounds: [[-122.5, 37.7], [-122.3, 37.9]],
|
|
44
|
+
* minZoom: 10,
|
|
45
|
+
* maxZoom: 14,
|
|
46
|
+
* styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
|
|
47
|
+
* },
|
|
48
|
+
* {
|
|
49
|
+
* onProgress: ({ phase, completed, total, percentage }) => {
|
|
50
|
+
* console.log(`[${phase}] ${completed}/${total} (${percentage.toFixed(1)}%)`);
|
|
51
|
+
* },
|
|
52
|
+
* }
|
|
53
|
+
* );
|
|
45
54
|
* ```
|
|
46
55
|
*/
|
|
47
56
|
export { OfflineMapManager } from './managers/offlineMapManager';
|