@yarrow-uz/yarrow-map-web-sdk 1.0.46 → 1.0.47

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 CHANGED
@@ -1,1045 +1,58 @@
1
- # Yarrow Map Web SDK Documentation
1
+ # @yarrow-uz/yarrow-map-web-sdk
2
2
 
3
- This document provides a comprehensive guide to using the Yarrow Map Web SDK for embedding and interacting with Yarrow maps in your web application.
3
+ A JavaScript SDK for embedding interactive maps and routing in web applications.
4
4
 
5
- ## Table of Contents
5
+ ## Features
6
6
 
7
- - [Getting Started](#getting-started)
8
- - [Installation](#installation)
9
- - [Initialization](#initialization)
10
- - [Configuration Options](#configuration-options)
11
- - [React Usage](#react-usage)
12
- - [Basic Map Manipulation](#basic-map-manipulation)
13
- - [Changing the Map Style](#changing-the-map-style)
14
- - [Changing the Map Theme](#changing-the-map-theme)
15
- - [Changing Brand Badge Position](#changing-brand-badge-position)
16
- - [Moving the Map View](#moving-the-map-view)
17
- - [Changing Background Color](#changing-background-color)
18
- - [Handling Events](#handling-events)
19
- - [Listen for Map Movement](#listen-for-map-movement)
20
- - [Listen for Map Clicks](#listen-for-map-clicks)
21
- - [Listen for Clicks on POIs or Buildings](#listen-for-clicks-on-pois-or-buildings)
22
- - [Working with Layers and Data](#working-with-layers-and-data)
23
- - [Adding a GeoJSON Layer](#adding-a-geojson-layer)
24
- - [Advanced Layer Configuration](#advanced-layer-configuration)
25
- - [Adding and Removing Markers](#adding-and-removing-markers)
26
- - [Removing a Layer](#removing-a-layer)
27
- - [Routing](#routing)
28
- - [Building and Displaying a Simple Route](#building-and-displaying-a-simple-route)
29
- - [Building and Displaying a Multi-Stop Route](#building-and-displaying-a-multi-stop-route)
30
- - [Clearing Routes](#clearing-routes)
31
- - [Rendering Multiple Routes](#rendering-multiple-routes)
32
- - [Search](#search)
33
- - [Highlighting Search Results](#highlighting-search-results)
34
- - [Advanced Search Configuration](#advanced-search-configuration)
35
- - [Public Transport](#public-transport)
36
- - [Displaying Real-Time Bus Locations](#displaying-real-time-bus-locations)
37
- - [Clearing Bus Routes](#clearing-bus-routes)
38
- - [Utility Methods](#utility-methods)
39
- - [Calculating Bounding Box](#calculating-bounding-box)
40
- - [Advanced Features](#advanced-features)
41
- - [Custom Icons and Styling](#custom-icons-and-styling)
42
- - [Performance Optimization](#performance-optimization)
43
- - [API Reference](#api-reference)
7
+ - Interactive map embedding with custom styling
8
+ - Markers and annotations
9
+ - Route planning and visualization
10
+ - Search functionality
11
+ - Navigation controls
12
+ - Offline tile caching
13
+ - React components support
44
14
 
45
- ---
46
-
47
- ## Getting Started
48
-
49
- ### Installation
50
-
51
- First, add the Yarrow Map Web SDK to your project using your preferred package manager.
15
+ ## Installation
52
16
 
53
17
  ```bash
54
18
  npm install @yarrow-uz/yarrow-map-web-sdk
55
19
  ```
56
20
 
57
- ### Local Development
58
-
59
- When running your application locally, serve it on **port 8080** to avoid CORS issues with the map API. Running on any other port will cause CORS errors.
60
-
61
- ### Initialization
62
-
63
- To get started, you need to create an instance of `YarrowMap`. This requires a configuration object that specifies the container element, center coordinates, and zoom level.
64
-
65
- **Important - Coordinate Format**: This SDK uses `[longitude, latitude]` format for map configuration (matching MapLibre GL convention), but `[latitude, longitude]` format for all other methods like routing and markers (matching common usage).
21
+ ## Usage
66
22
 
67
23
  ```javascript
68
24
  import { YarrowMap } from '@yarrow-uz/yarrow-map-web-sdk';
69
25
 
70
- // Configuration for the map
71
- const mapConfig = {
72
- container: 'map', // ID of the div element to render the map in
73
- center: [69.2401, 41.2995], // Initial center [longitude, latitude] - MapLibre convention
74
- zoom: 12, // Initial zoom level
75
- };
76
-
77
- // Create a new map instance
78
- const yarrowMap = new YarrowMap(mapConfig);
79
-
80
- // Initialize the map
81
- yarrowMap.init().then(() => {
82
- console.log('Map initialized successfully!');
83
- });
84
- ```
85
-
86
- **Note:** By default, all MapLibre controls (zoom, navigation, attribution) are automatically removed during initialization. Use MapLibre's `addControl()` method if you need to add specific controls.
87
-
88
- ### Configuration Options
89
-
90
- The `YarrowMapConfig` class accepts a single configuration object:
91
-
92
- ```javascript
93
- const mapConfig = new YarrowMapConfig({
94
- container, // string | HTMLElement
95
- center, // [number, number] - [lng, lat]
96
- apiKey, // string - Required, get from https://dashboard.yarrow.uz/
97
- zoom, // number (default: 10)
98
- minZoom, // number (default: 0)
99
- maxZoom, // number (default: 19)
100
- theme, // 'light' | 'dark' (default: 'light')
101
- cache, // { enabled?: boolean, lifespanDays?: number }
102
- brandBadgePosition, // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
103
- controls // { enabled?: boolean, position?: 'left'|'left-top'|'left-bottom'|'right'|'right-top'|'right-bottom', zoom?: boolean, compass?: boolean }
104
- });
105
- ```
106
-
107
- **Example with all options:**
108
-
109
- ```javascript
110
- import { YarrowMap, YarrowMapConfig } from '@yarrow-uz/yarrow-map-web-sdk';
111
-
112
- const mapConfig = new YarrowMapConfig({
113
- container: 'map',
114
- center: [69.2401, 41.2995],
26
+ const map = new YarrowMap({
27
+ container: 'map-container',
28
+ apiKey: 'your-api-key',
29
+ style: 'your-style-url',
30
+ center: [55.3, 25.3],
115
31
  zoom: 12,
116
- minZoom: 5,
117
- maxZoom: 18,
118
- apiKey: 'YOUR_API_KEY', // Required - get from https://dashboard.yarrow.uz/
119
- theme: 'dark',
120
- cache: {
121
- enabled: true, // Enable local persistent cache (default: false)
122
- lifespanDays: 30 // Cache lifespan in days (default: 30)
123
- },
124
- brandBadgePosition: 'top-right',
125
- controls: {
126
- enabled: true, // Yarrow controls are OFF by default
127
- position: 'right-bottom', // Optional placement: left/left-top/left-bottom/right/right-top/right-bottom
128
- zoom: true, // Optional
129
- compass: true // Optional
130
- },
131
32
  });
132
33
 
133
- const yarrowMap = new YarrowMap(mapConfig);
134
- yarrowMap.init().then(() => {
135
- console.log('Map initialized successfully!');
34
+ map.on('load', () => {
35
+ console.log('Map loaded!');
136
36
  });
137
37
  ```
138
38
 
139
- When controls and the brand badge are placed in the same corner (for example `right-bottom` with `brandBadgePosition: 'bottom-right'`), the SDK automatically adds spacing so they do not overlap.
140
-
141
- ### React Usage
142
-
143
- React APIs are exported from the `@yarrow-uz/yarrow-map-web-sdk/react` subpath.
39
+ ### React
144
40
 
145
- ```tsx
41
+ ```jsx
146
42
  import { YarrowMapView } from '@yarrow-uz/yarrow-map-web-sdk/react';
147
43
 
148
- export const MapScreen = () => {
44
+ function App() {
149
45
  return (
150
46
  <YarrowMapView
151
- config={{
152
- center: [69.2401, 41.2995],
153
- zoom: 12,
154
- apiKey: 'YOUR_API_KEY', // Required - get from https://dashboard.yarrow.uz/
155
- brandBadgePosition: 'bottom-left',
156
- }}
157
- style={{ width: '100%', height: '600px' }}
47
+ apiKey="your-api-key"
48
+ style="your-style-url"
49
+ center={[55.3, 25.3]}
50
+ zoom={12}
158
51
  />
159
52
  );
160
- };
161
- ```
162
-
163
- You can also use the hook for custom composition:
164
-
165
- ```tsx
166
- import { useYarrowMap } from '@yarrow-uz/yarrow-map-web-sdk/react';
167
-
168
- export const MapScreen = () => {
169
- const { containerRef, isReady, error } = useYarrowMap({
170
- config: {
171
- center: [69.2401, 41.2995],
172
- zoom: 12,
173
- brandBadgePosition: 'bottom-right',
174
- },
175
- });
176
-
177
- return (
178
- <div>
179
- <div ref={containerRef} style={{ width: '100%', height: '600px' }} />
180
- {isReady && <p>Map ready</p>}
181
- {error && <p>Failed to initialize map</p>}
182
- </div>
183
- );
184
- };
185
- ```
186
-
187
- **SSR note:** The React integration initializes the map only on the client side.
188
-
189
- ## Basic Map Manipulation
190
-
191
- ### Changing the Map Style
192
-
193
- You can change the map's visual style. The available styles are `satellite`, `hybrid`, and the default map style.
194
-
195
- The map supports up to **85-degree pitch** for 3D perspective views.
196
-
197
- ```javascript
198
- // Switch to satellite view
199
- yarrowMap.changeStyles('satellite');
200
-
201
- // Switch to hybrid view (satellite with labels)
202
- yarrowMap.changeStyles('hybrid');
203
-
204
- // Switch back to the default map style
205
- yarrowMap.changeStyles();
206
- ```
207
-
208
- ### Changing the Map Theme
209
-
210
- You can set the initial theme in the configuration or switch between light and dark themes dynamically after initialization.
211
-
212
- **Setting initial theme:**
213
-
214
- ```javascript
215
- // Initialize with dark theme
216
- const mapConfig = new YarrowMapConfig({
217
- container: 'map',
218
- center: [69.2401, 41.2995],
219
- zoom: 12,
220
- minZoom: 5,
221
- maxZoom: 18,
222
- apiKey: 'YOUR_API_KEY', // Required - get from https://dashboard.yarrow.uz/
223
- theme: 'dark', // Set initial theme to dark
224
- });
225
- ```
226
-
227
- **Switching theme dynamically:**
228
-
229
- ```javascript
230
- // Switch to dark mode
231
- await yarrowMap.changeTheme('dark');
232
-
233
- // Switch to light mode (default)
234
- await yarrowMap.changeTheme('light');
235
- ```
236
-
237
- **Features:**
238
- - Automatically re-fetches appropriate styles from the server
239
- - Updates all map layers to match the theme
240
- - Preserves custom icons and markers
241
- - Seamless theme transition
242
-
243
- ### Changing Brand Badge Position
244
-
245
- You can set the initial badge position in config or change it dynamically after map initialization.
246
-
247
- ```javascript
248
- // Move badge to the top-right corner
249
- yarrowMap.changeBrandBadgePosition('top-right');
250
-
251
- // Other values: 'top-left' | 'bottom-left' | 'bottom-right'
252
- ```
253
-
254
- ### Moving the Map View
255
-
256
- You can programmatically move the map to a new location or fit it to a specific geographic area.
257
-
258
- **Zooming to a specific point:**
259
-
260
- ```javascript
261
- // Fly to a new location with a specific zoom level
262
- yarrowMap.zoomTo(41.3111, 69.2797, 15); // Latitude, Longitude, Zoom Level
263
- ```
264
-
265
- **Fitting the map to a set of features:**
266
-
267
- This is useful when you want to display a set of points, lines, or polygons and ensure they are all visible.
268
-
269
- ```javascript
270
- const geojsonData = {
271
- type: 'FeatureCollection',
272
- features: [
273
- // Your GeoJSON features here
274
- ],
275
- };
276
-
277
- yarrowMap.fitBounds(geojsonData);
278
- ```
279
-
280
- ### Changing Background Color
281
-
282
- You can change the background color of the map programmatically:
283
-
284
- ```javascript
285
- // Change the map background to a custom color
286
- yarrowMap.changeBackgroundColor('#f0f0f0'); // Light gray background
287
- ```
288
-
289
- **Note:** This method waits for the map style to be fully loaded before applying the background color change.
290
-
291
- ## Handling Events
292
-
293
- You can listen for various user interactions with the map.
294
-
295
- ### Listen for Map Movement
296
-
297
- Execute a callback function whenever the map finishes moving.
298
-
299
- ```javascript
300
- yarrowMap.onMoveEnd((lat, lng, zoom) => {
301
- console.log(`Map moved to: ${lat}, ${lng} with zoom: ${zoom}`);
302
- });
303
- ```
304
-
305
- ### Listen for Map Clicks
306
-
307
- Execute a callback when the user clicks on the map.
308
-
309
- ```javascript
310
- yarrowMap.onMapClick((lat, lng) => {
311
- console.log(`Map clicked at: ${lat}, ${lng}`);
312
- });
313
- ```
314
-
315
- ### Listen for Clicks on POIs or Buildings
316
-
317
- You can add click listeners to specific groups of features on the map, like points of interest (POIs) or buildings.
318
-
319
- ```javascript
320
- // Listen for clicks on POIs
321
- yarrowMap.onIconClick('pois', (lat, lng, properties) => {
322
- console.log('POI clicked:', properties);
323
- });
324
-
325
- // Listen for clicks on buildings
326
- yarrowMap.onIconClick('buildings', (lat, lng, properties) => {
327
- console.log('Building clicked:', properties);
328
- });
329
-
330
- // Note: onLayerClick is an alias for onIconClick (they are the same method)
331
- yarrowMap.onLayerClick('pois', (lat, lng, properties) => {
332
- console.log('Same as onIconClick');
333
- });
334
- ```
335
-
336
- ## Working with Layers and Data
337
-
338
- ### Adding a GeoJSON Layer
339
-
340
- You can add custom data to the map in the form of a GeoJSON layer. This is useful for displaying points, lines, or polygons.
341
-
342
- ```javascript
343
- const myData = {
344
- type: 'FeatureCollection',
345
- features: [
346
- {
347
- type: 'Feature',
348
- geometry: {
349
- type: 'Point',
350
- coordinates: [69.2797, 41.3111],
351
- },
352
- properties: {
353
- name: 'My Point',
354
- },
355
- },
356
- ],
357
- };
358
-
359
- yarrowMap.addLayer(
360
- 'my-custom-layer', // A unique name for the layer
361
- 'circle', // The type of layer (e.g., 'circle', 'line', 'fill', 'symbol')
362
- myData,
363
- {
364
- 'circle-radius': 10,
365
- 'circle-color': '#ff0000',
366
- }
367
- );
368
- ```
369
-
370
- ### Advanced Layer Configuration
371
-
372
- The `addLayer` method supports advanced configuration options for different layer types:
373
-
374
- ```javascript
375
- yarrowMap.addLayer(
376
- layerName, // string - Unique identifier for the layer
377
- layerType, // Layer type: 'symbol', 'fill', 'line', 'background', 'raster', 'circle', 'heatmap', 'fill-extrusion', 'hillshade'
378
- featureCollection, // GeoJSON FeatureCollection
379
- paint, // Paint properties object
380
- layout, // Layout properties object
381
- iconSettings, // Icon configuration (width, height)
382
- options // Optional: { sourceId?: string, filter?: LayerFilter }
383
- );
384
- ```
385
-
386
- ### Managing Sources Explicitly
387
-
388
- ```javascript
389
- yarrowMap.addSource('vehicles-source', vehicleFeatureCollection);
390
- yarrowMap.updateSourceData('vehicles-source', nextVehicleFeatureCollection);
391
-
392
- yarrowMap.addLayer(
393
- 'active-vehicles',
394
- 'circle',
395
- nextVehicleFeatureCollection,
396
- {
397
- 'circle-radius': ['interpolate', ['linear'], ['zoom'], 10, 4, 16, 10],
398
- 'circle-color': ['case', ['==', ['get', 'status'], 'active'], '#16a34a', '#9ca3af']
399
- },
400
- {},
401
- {},
402
- {
403
- sourceId: 'vehicles-source',
404
- filter: ['==', ['get', 'status'], 'active']
405
- }
406
- );
407
- ```
408
-
409
- ### Feature State and Rendered Queries
410
-
411
- ```javascript
412
- yarrowMap.setFeatureState(
413
- { source: 'vehicles-source', id: 101 },
414
- { selected: true }
415
- );
416
-
417
- const features = yarrowMap.queryRenderedFeatures({ layers: ['active-vehicles'] });
418
- ```
419
-
420
- **Symbol layer with custom icons:**
421
-
422
- ```javascript
423
- const symbolData = {
424
- type: 'FeatureCollection',
425
- features: [
426
- {
427
- type: 'Feature',
428
- geometry: { type: 'Point', coordinates: [69.2797, 41.3111] },
429
- properties: { name: 'Custom Point' }
430
- }
431
- ]
432
- };
433
-
434
- yarrowMap.addLayer(
435
- 'custom-symbols',
436
- 'symbol',
437
- symbolData,
438
- {
439
- 'text-halo-color': '#ffffff',
440
- 'text-halo-width': 2
441
- },
442
- {
443
- 'icon-image': 'custom-icon',
444
- 'icon-image-data': 'data:image/png;base64,...', // Base64 image data
445
- 'icon-size': 0.8,
446
- 'icon-allow-overlap': true,
447
- 'text-field': ['get', 'name'],
448
- 'text-offset': [0, 1.5],
449
- 'text-anchor': 'top',
450
- 'text-size': 14
451
- },
452
- {
453
- width: 32, // Icon width
454
- height: 32 // Icon height
455
- }
456
- );
457
- ```
458
-
459
- **Line layer with styling:**
460
-
461
- ```javascript
462
- const lineData = {
463
- type: 'FeatureCollection',
464
- features: [
465
- {
466
- type: 'Feature',
467
- geometry: {
468
- type: 'LineString',
469
- coordinates: [[69.240, 41.299], [69.280, 41.311]]
470
- }
471
- }
472
- ]
473
- };
474
-
475
- yarrowMap.addLayer(
476
- 'custom-line',
477
- 'line',
478
- lineData,
479
- {
480
- 'line-color': '#3b82f6',
481
- 'line-width': 4,
482
- 'line-opacity': 0.8
483
- },
484
- {
485
- 'line-join': 'round',
486
- 'line-cap': 'round'
487
- }
488
- );
489
- ```
490
-
491
- ### Adding and Removing Markers
492
-
493
- You can add markers to the map to indicate specific locations.
494
-
495
- ```javascript
496
- // Add a simple red marker (default color)
497
- const marker = yarrowMap.addMarker([41.3111, 69.2797]); // [latitude, longitude]
498
-
499
- // Add a marker with all options
500
- const customMarker = yarrowMap.addMarker([41.2995, 69.2401], {
501
- element: customElement, // HTMLElement - Custom marker element
502
- color: '#0000ff', // string - Marker color (default: '#FF0000')
503
- draggable: true, // boolean - Allow dragging (default: false)
504
- anchor: 'bottom', // Anchor position: 'center', 'top', 'bottom', 'left', 'right', 'top-left', 'top-right', 'bottom-left', 'bottom-right'
505
- onClick: () => { // function - Click event handler
506
- console.log('Marker clicked!');
507
- }
508
- });
509
-
510
- // Add a marker with custom HTML element
511
- const customElement = document.createElement('div');
512
- customElement.innerHTML = '📍';
513
- customElement.style.fontSize = '24px';
514
-
515
- const htmlMarker = yarrowMap.addMarker([41.3050, 69.2500], {
516
- element: customElement,
517
- anchor: 'center'
518
- });
519
-
520
- // Remove a marker
521
- yarrowMap.removeMarker(marker);
522
- ```
523
-
524
- **Marker Options:**
525
- - `element`: Custom HTML element for the marker
526
- - `color`: Marker color (default: '#FF0000')
527
- - `draggable`: Whether the marker can be dragged (default: false)
528
- - `anchor`: Anchor point of the marker relative to its coordinates
529
- - `onClick`: Click event handler function
530
-
531
- ### Removing a Layer
532
-
533
- You can remove a layer that you've previously added.
534
-
535
- ```javascript
536
- yarrowMap.removeLayer('my-custom-layer');
537
- ```
538
-
539
- ## Routing
540
-
541
- The SDK provides powerful routing capabilities.
542
-
543
- ### Building and Displaying a Simple Route
544
-
545
- Calculate and display a route between a start and end point.
546
-
547
- ```javascript
548
- const start = [41.2995, 69.2401]; // [latitude, longitude]
549
- const end = [41.3111, 69.2797];
550
- const profile = 'car'; // 'car', 'bicycle', or 'pedestrian'
551
-
552
- yarrowMap.buildRouteWithLabels(start, end, profile).then(({ features, directions }) => {
553
- console.log('Route built:', features);
554
- console.log('Directions:', directions);
555
- });
556
- ```
557
-
558
- ### Building and Displaying a Multi-Stop Route
559
-
560
- You can also create a route that passes through multiple waypoints.
561
-
562
- ```javascript
563
- const coordinates = [
564
- [41.2995, 69.2401], // Start [latitude, longitude]
565
- [41.3111, 69.2797], // Waypoint 1
566
- [41.325, 69.285], // End
567
- ];
568
- const profile = 'car';
569
- const language = 'en'; // Optional: 'en', 'ru', etc. (default: 'ru')
570
-
571
- yarrowMap.buildMultiSegmentRouteWithLabels(coordinates, profile, language).then(({ features, directions }) => {
572
- console.log('Multi-segment route built:', features);
573
- console.log('Directions:', directions);
574
- });
575
- ```
576
-
577
- **Important Note**: The SDK uses `[latitude, longitude]` format for all user-facing coordinate parameters (routing, markers, etc.), which is then internally converted to MapLibre's `[longitude, latitude]` format where needed.
578
-
579
- ### Clearing Routes
580
-
581
- To remove all route-related layers from the map:
582
-
583
- ```javascript
584
- yarrowMap.clearAllRoutes();
585
- ```
586
-
587
- ### Rendering Multiple Routes
588
-
589
- You can render multiple route features with automatic color coding:
590
-
591
- ```javascript
592
- // Array of route features (GeoJSON LineString features)
593
- const routes = [
594
- {
595
- type: 'Feature',
596
- geometry: {
597
- type: 'LineString',
598
- coordinates: [[69.240, 41.299], [69.280, 41.311], [69.285, 41.315]]
599
- },
600
- properties: {
601
- duration: 15.5,
602
- distance: 2500
603
- }
604
- },
605
- {
606
- type: 'Feature',
607
- geometry: {
608
- type: 'LineString',
609
- coordinates: [[69.240, 41.299], [69.275, 41.308], [69.285, 41.315]]
610
- },
611
- properties: {
612
- duration: 18.2,
613
- distance: 3000
614
- }
615
- }
616
- ];
617
-
618
- // Render routes with default styling
619
- yarrowMap.renderRoutes(routes);
620
-
621
- // Render routes with custom base layer name
622
- yarrowMap.renderRoutes(routes, 'my-custom-routes');
623
- ```
624
-
625
- **Features:**
626
- - Automatically assigns different colors to each route (#3b82f6, #10b981, #f59e0b, #ef4444, #8b5cf6)
627
- - Creates separate layers for each route (`{baseLayerName}-0`, `{baseLayerName}-1`, etc.)
628
- - Default base layer name is 'route' if not specified
629
-
630
- ## Search
631
-
632
- ### Highlighting Search Results
633
-
634
- You can perform a search and display the results on the map. The search is performed around the current map center.
635
-
636
- ```javascript
637
- const query = 'Tashkent';
638
-
639
- const clearHighlights = yarrowMap.highlightSearchResults(query, {
640
- zoomToResults: true, // Automatically zoom to fit the results
641
- onResultsUpdate: (results) => {
642
- console.log('Search results:', results);
643
- },
644
- onLoadingStateChange: (state) => {
645
- // state can be 'firstRender', 'rerender', or false
646
- console.log('Loading state:', state);
647
- }
648
- });
649
-
650
- // To remove the search results from the map later
651
- // clearHighlights();
652
- ```
653
-
654
- ### Advanced Search Configuration
655
-
656
- The `highlightSearchResults` method accepts comprehensive configuration options:
657
-
658
- ```javascript
659
- const clearFunction = yarrowMap.highlightSearchResults('Tashkent', {
660
- layerName: 'my-search-layer', // Custom layer name (default: 'search-results')
661
- iconImage: 'custom-search-icon', // Custom icon image name
662
- highlightColor: '#ff6b35', // Custom highlight color
663
- pulseAnimation: true, // Enable pulse animation (default: false)
664
- zoomToResults: false, // Auto-zoom to results (default: true)
665
-
666
- // Event handlers
667
- onIconClick: (lat, lng, properties) => {
668
- console.log('Search result clicked:', { lat, lng, properties });
669
- // Custom click behavior
670
- },
671
-
672
- onResultsUpdate: (results) => {
673
- console.log(`Found ${results.length} search results`);
674
- // Handle results update
675
- },
676
-
677
- onLoadingStateChange: (state) => {
678
- // state can be 'firstRender', 'rerender', or false
679
- if (state === 'firstRender') {
680
- console.log('Initial search loading...');
681
- } else if (state === 'rerender') {
682
- console.log('Updating search results...');
683
- } else {
684
- console.log('Search loading complete');
685
- }
686
- }
687
- });
688
-
689
- // Clear search results when done
690
- clearFunction();
691
- ```
692
-
693
- **Configuration Options:**
694
- - `layerName`: Custom name for the search results layer
695
- - `iconImage`: Custom icon image to use for search results
696
- - `highlightColor`: Color for highlighting search results
697
- - `pulseAnimation`: Enable/disable pulse animation effect
698
- - `zoomToResults`: Automatically zoom to fit search results
699
- - `onIconClick`: Callback when a search result icon is clicked
700
- - `onResultsUpdate`: Callback when search results are updated
701
- - `onLoadingStateChange`: Callback for loading state changes
702
-
703
- **Features:**
704
- - Automatic re-searching when the map is moved (debounced)
705
- - Distance-based filtering (minimum 500m movement triggers re-search)
706
- - Automatic cleanup of previous search results
707
- - Real-time loading state tracking
708
-
709
- ## Public Transport
710
-
711
- ### Displaying Real-Time Bus Locations
712
-
713
- You can display the real-time locations of buses on the map.
714
-
715
- **Show buses for a specific route:**
716
-
717
- ```javascript
718
- const routeId = 'some-route-id';
719
- yarrowMap.showBusRoute(routeId).then(clearBusRoute => {
720
- // To stop showing the bus route later
721
- // clearBusRoute();
722
- });
723
- ```
724
-
725
- **Show all buses in the current map view:**
726
-
727
- If you don't provide a `route_id`, the map will show all buses within the visible area.
728
-
729
- ```javascript
730
- yarrowMap.showBusRoute().then(clearBusRoutes => {
731
- // To stop showing all bus routes
732
- // clearBusRoutes();
733
- });
734
- ```
735
-
736
- ### Clearing Bus Routes
737
-
738
- The `showBusRoute` method returns a cleanup function that you can call to stop displaying bus locations and remove all related data:
739
-
740
- ```javascript
741
- // Store the cleanup function
742
- const clearBuses = await yarrowMap.showBusRoute('route-123');
743
-
744
- // Later, clear the bus route display
745
- clearBuses();
746
- ```
747
-
748
- **What the cleanup function does:**
749
- - Stops the automatic bus location updates (15-second interval)
750
- - Removes all bus markers from the map
751
- - Removes all route layers from the map
752
- - Removes map move event listeners
753
- - Clears internal caches (SVG cache, etc.)
754
-
755
- **Advanced Bus Route Features:**
756
-
757
- **Smooth Bus Animation:**
758
- Buses animate smoothly between positions, providing a realistic tracking experience:
759
- - 16-second animation duration between position updates
760
- - Uses `requestAnimationFrame` for smooth 60fps interpolation
761
- - Each bus has independent position tracking (`current` vs `target`)
762
- - Animation starts automatically when buses are displayed
763
-
764
- ```javascript
765
- // Buses will animate smoothly between updates
766
- const clearBuses = await yarrowMap.showBusRoute('route-123');
767
- ```
768
-
769
- **Performance Optimization:**
770
- - Maximum 100 buses displayed at once (randomly selected if more exist)
771
- - 5km radius filtering for general bus display (no route_id)
772
- - Automatic viewport filtering for subsequent updates
773
- - SVG icon caching for better performance
774
- - Debounced map movement updates (500ms delay)
775
-
776
- **Automatic Updates:**
777
- - Bus locations update every 16 seconds
778
- - Map movement triggers bus location refresh (for general display)
779
- - Distance-based filtering (minimum 500m movement)
780
-
781
- ## Utility Methods
782
-
783
- ### Calculating Bounding Box
784
-
785
- The SDK provides a utility method to calculate the bounding box of GeoJSON data:
786
-
787
- ```javascript
788
- const geojsonData = {
789
- type: 'FeatureCollection',
790
- features: [
791
- {
792
- type: 'Feature',
793
- geometry: {
794
- type: 'Point',
795
- coordinates: [69.2797, 41.3111]
796
- }
797
- },
798
- {
799
- type: 'Feature',
800
- geometry: {
801
- type: 'LineString',
802
- coordinates: [[69.240, 41.299], [69.280, 41.311]]
803
- }
804
- }
805
- ]
806
- };
807
-
808
- const boundingBox = yarrowMap.getBoundingBox(geojsonData);
809
- console.log(boundingBox);
810
- // Output: { xMin: 69.240, xMax: 69.280, yMin: 41.299, yMax: 41.3111 }
811
- ```
812
-
813
- **Supported Geometry Types:**
814
- - Point
815
- - LineString
816
- - Polygon
817
-
818
- The bounding box contains:
819
- - `xMin`: Minimum longitude
820
- - `xMax`: Maximum longitude
821
- - `yMin`: Minimum latitude
822
- - `yMax`: Maximum latitude
823
-
824
- ### Clearing Local Cache
825
-
826
- You can clear cached map resources programmatically:
827
-
828
- ```javascript
829
- await yarrowMap.clearCache();
830
- ```
831
-
832
- ## Advanced Features
833
-
834
- ### Custom Icons and Styling
835
-
836
- **Loading Custom Icons:**
837
- The SDK automatically loads and caches icons from the server during initialization. You can reference these icons by name in your layers:
838
-
839
- ```javascript
840
- // Icons are automatically available after init()
841
- yarrowMap.init().then(() => {
842
- // Use server-provided icons
843
- yarrowMap.addLayer(
844
- 'poi-layer',
845
- 'symbol',
846
- poiData,
847
- {},
848
- {
849
- 'icon-image': ['get', 'icon_img'], // References the icon from feature properties
850
- 'icon-size': 0.7
851
- }
852
- );
853
- });
854
- ```
855
-
856
- **Custom Icon Data:**
857
- You can also provide custom icon data directly:
858
-
859
- ```javascript
860
- yarrowMap.addLayer(
861
- 'custom-icons',
862
- 'symbol',
863
- symbolData,
864
- {},
865
- {
866
- 'icon-image': 'my-custom-icon',
867
- 'icon-image-data': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...',
868
- 'icon-size': 1.0
869
- },
870
- {
871
- width: 48,
872
- height: 48
873
- }
874
- );
875
- ```
876
-
877
- ### Performance Optimization
878
-
879
- **Layer Management:**
880
- - Layers are automatically cleaned up when re-added with the same name
881
- - Sources are removed along with layers to prevent memory leaks
882
- - Icon images are cached to avoid redundant loading
883
-
884
- **Bus Route Optimization:**
885
- - Maximum bus limit prevents performance issues with large datasets
886
- - Viewport-based filtering reduces unnecessary marker creation
887
- - SVG caching improves rendering performance
888
- - Debounced updates prevent excessive API calls
889
-
890
- **Memory Management:**
891
- - Automatic cleanup of intervals and event listeners
892
- - Cache clearing on component destruction
893
- - Proper marker removal prevents memory leaks
894
-
895
- **Best Practices:**
896
-
897
- 1. **Always clean up resources:**
898
- ```javascript
899
- const clearSearch = yarrowMap.highlightSearchResults('query');
900
- const clearBuses = await yarrowMap.showBusRoute();
901
-
902
- // When done, clean up
903
- clearSearch();
904
- clearBuses();
905
- ```
906
-
907
- 2. **Reuse layer names for dynamic content:**
908
- ```javascript
909
- // This will automatically clean up the previous layer
910
- yarrowMap.addLayer('dynamic-layer', 'circle', newData, paint);
911
- ```
912
-
913
- 3. **Use meaningful layer names:**
914
- ```javascript
915
- // Good: descriptive and unique
916
- yarrowMap.addLayer('user-locations-2024', 'symbol', userData);
917
-
918
- // Avoid: generic names that might conflict
919
- yarrowMap.addLayer('layer1', 'symbol', userData);
920
- ```
921
-
922
- 4. **Handle errors appropriately:**
923
- ```javascript
924
- try {
925
- await yarrowMap.buildRouteWithLabels(start, end, 'car');
926
- } catch (error) {
927
- console.error('Route building failed:', error);
928
- // Handle error appropriately
929
53
  }
930
54
  ```
931
55
 
932
- ---
933
-
934
- ## API Reference
935
-
936
- ### YarrowMapConfig Class
937
-
938
- ```typescript
939
- constructor(
940
- config: {
941
- container: string | HTMLElement;
942
- center: [number, number];
943
- zoom?: number; // default: 10
944
- minZoom?: number; // default: 0
945
- maxZoom?: number; // default: 19
946
- theme?: 'light' | 'dark'; // default: 'light'
947
- cache?: {
948
- enabled?: boolean; // default: false
949
- lifespanDays?: number; // default: 30 (1 month)
950
- };
951
- brandBadgePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
952
- controls?: {
953
- enabled?: boolean; // default: false
954
- position?:
955
- | 'left'
956
- | 'left-top'
957
- | 'left-bottom'
958
- | 'right'
959
- | 'right-top'
960
- | 'right-bottom';
961
- zoom?: boolean; // default: true
962
- compass?: boolean; // default: true
963
- };
964
- }
965
- )
966
- ```
967
-
968
- ### YarrowMap Class Methods
969
-
970
- | Method | Parameters | Return Type | Description |
971
- |--------|------------|-------------|-------------|
972
- | `init()` | None | `Promise<void>` | Initialize the map with styles and icons |
973
- | `changeStyles(styleType?)` | `styleType?: 'satellite' \| 'hybrid'` | `Promise<any>` | Change map style |
974
- | `changeTheme(theme)` | `theme: 'light' \| 'dark'` | `Promise<any>` | Switch between light and dark themes |
975
- | `changeBrandBadgePosition(position)` | `position: 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `BrandBadgePosition` | Change brand badge corner position at runtime |
976
- | `zoomTo(lat, lng, zoom)` | `lat: number, lng: number, zoom: number` | `void` | Fly to specific coordinates |
977
- | `fitBounds(data)` | `data: GeoJSON` | `void` | Fit map to show all features |
978
- | `getBoundingBox(data)` | `data: GeoJSON` | `BoundingBox` | Calculate bounding box of features |
979
- | `onMoveEnd(callback)` | `callback: (lat, lng, zoom) => void` | `void` | Listen for map movement end |
980
- | `onMapClick(callback)` | `callback: (lat, lng) => void` | `void` | Listen for map clicks |
981
- | `onIconClick(layerGroup, callback)` | `layerGroup: 'pois' \| 'buildings', callback: Function` | `void` | Listen for icon clicks |
982
- | `onLayerClick(layerGroup, callback)` | `layerGroup: 'pois' \| 'buildings', callback: Function` | `void` | Alias for onIconClick (same method) |
983
- | `changeBackgroundColor(color)` | `color: string` | `void` | Change map background color |
984
- | `addSource()` | `sourceId, data` | `void` | Add/replace a GeoJSON source |
985
- | `updateSourceData()` | `sourceId, data` | `void` | Update data for an existing GeoJSON source (or create it) |
986
- | `addLayer()` | `layerName, layerType, featureCollection, paint?, layout?, iconSettings?, options?` | `void` | Add a layer to the map (supports `sourceId` and `filter`) |
987
- | `setFeatureState()` | `featureIdentifier, state` | `void` | Set state for a specific feature |
988
- | `queryRenderedFeatures()` | `geometryOrOptions?, options?` | `MapGeoJSONFeature[]` | Query currently rendered features (supports `{ layers }`) |
989
- | `removeLayer(layerName)` | `layerName: string` | `void` | Remove a layer from the map |
990
- | `addMarker(coordinates, options?)` | `coordinates: [lat, lng], options?: MarkerOptions` | `Marker \| null` | Add a marker to the map |
991
- | `removeMarker(marker)` | `marker: Marker` | `void` | Remove a marker from the map |
992
- | `renderRoutes(routes, baseLayerName?)` | `routes: Feature[], baseLayerName?: string` | `void` | Render multiple route features |
993
- | `buildRouteWithLabels()` | `start: [lat, lng], end: [lat, lng], profile: string` | `Promise<RouteResult>` | Build and display a route with labels |
994
- | `buildMultiSegmentRouteWithLabels()` | `coordinates: [lat, lng][], profile: string, language?: string` | `Promise<RouteResult>` | Build multi-segment route |
995
- | `clearAllRoutes()` | None | `void` | Clear all route layers and popups |
996
- | `clearCache()` | None | `Promise<void>` | Clear local persistent cache |
997
- | `highlightSearchResults()` | `query: string, options?: SearchOptions` | `() => void` | Highlight search results with cleanup function |
998
- | `showBusRoute(routeId?)` | `routeId?: string` | `Promise<() => void>` | Show bus locations with cleanup function |
999
-
1000
- ### Type Definitions
1001
-
1002
- ```typescript
1003
- interface BoundingBox {
1004
- xMin: number;
1005
- xMax: number;
1006
- yMin: number;
1007
- yMax: number;
1008
- }
1009
-
1010
- interface RouteResult {
1011
- features: any[];
1012
- directions: any[];
1013
- }
1014
-
1015
- interface MarkerOptions {
1016
- element?: HTMLElement;
1017
- color?: string;
1018
- draggable?: boolean;
1019
- anchor?: 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
1020
- onClick?: () => void;
1021
- }
1022
-
1023
- interface SearchOptions {
1024
- layerName?: string;
1025
- iconImage?: string;
1026
- highlightColor?: string;
1027
- pulseAnimation?: boolean;
1028
- zoomToResults?: boolean;
1029
- onIconClick?: (lat: number, lng: number, properties: any) => void;
1030
- onResultsUpdate?: (results: any[]) => void;
1031
- onLoadingStateChange?: (state: 'firstRender' | 'rerender' | false) => void;
1032
- }
1033
- ```
1034
-
1035
- ---
1036
-
1037
- ## Version Information
1038
-
1039
- - **Current Version**: 1.0.46
1040
- - **Dependencies**: maplibre-gl ^5.19.0
1041
- - **Changelog**: `CHANGELOG.md`
1042
-
1043
- ## Support
56
+ ## Documentation
1044
57
 
1045
- For issues, questions, or contributions, contact the Yarrow development team.
58
+ Full documentation available at https://sdk.yarrow.uz/web-sdk